From 54ae08e927ac63239a5d03a7fe399b0db98644c3 Mon Sep 17 00:00:00 2001 From: Javiera Munita Date: Thu, 30 Jul 2026 11:59:57 -0400 Subject: [PATCH 1/2] fix(PDYE-2075): modal para linkedin y google review --- src/atoms/Icons/Star.tsx | 16 +++ src/atoms/Icons/index.tsx | 1 + src/index.ts | 1 + .../LinkedinAndReview/ShareAndReviewModal.tsx | 108 ++++++++++++++++++ .../components/AfterShareContent.tsx | 67 +++++++++++ .../components/CustomCloseIcon.tsx | 14 +++ .../components/InitialShareContent.tsx | 99 ++++++++++++++++ src/organisms/LinkedinAndReview/index.ts | 1 + src/organisms/index.ts | 1 + tsconfig.types.json | 3 +- 10 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 src/atoms/Icons/Star.tsx create mode 100644 src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx create mode 100644 src/organisms/LinkedinAndReview/components/AfterShareContent.tsx create mode 100644 src/organisms/LinkedinAndReview/components/CustomCloseIcon.tsx create mode 100644 src/organisms/LinkedinAndReview/components/InitialShareContent.tsx create mode 100644 src/organisms/LinkedinAndReview/index.ts diff --git a/src/atoms/Icons/Star.tsx b/src/atoms/Icons/Star.tsx new file mode 100644 index 000000000..9dc8ad7b2 --- /dev/null +++ b/src/atoms/Icons/Star.tsx @@ -0,0 +1,16 @@ +import { Base, BaseProps } from './Base' + +export function Star(props: BaseProps): JSX.Element { + return ( + + + + ) +} + +Star.displayName = 'Star' diff --git a/src/atoms/Icons/index.tsx b/src/atoms/Icons/index.tsx index 72968ed75..e5a79506f 100644 --- a/src/atoms/Icons/index.tsx +++ b/src/atoms/Icons/index.tsx @@ -14,6 +14,7 @@ export * from './Multimedia' export * from './Profile' export * from './Remote' export * from './Schedule' +export * from './Star' export * from './Time' export * from './TinyAlertInfo' export * from './TinyAlertError' diff --git a/src/index.ts b/src/index.ts index 310caf1f9..2a25d267c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,7 @@ export { Eventos } from './organisms/Events' export { Resources } from './organisms/Resources' export { CalendarDropdown, EventsList } from './organisms/Calendar' export { UserDropdown } from './organisms/User' +export { ShareAndReviewModal } from './organisms/LinkedinAndReview' export type { AccesibleProfileMenuProps, ProfileMenuItem } from './organisms/User' // Tema diff --git a/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx b/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx new file mode 100644 index 000000000..d41e82181 --- /dev/null +++ b/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx @@ -0,0 +1,108 @@ +import { + Modal, + ModalOverlay, + ModalContent, + ModalContentProps, + IconButton, + IconButtonProps, + Flex, + FlexProps, +} from '@chakra-ui/react' +import { useEffect, useState } from 'react' + +import { vars } from '@theme' + +import { CustomCloseIcon } from './components/CustomCloseIcon' +import { InitialShareContent } from './components/InitialShareContent' +import { AfterShareContent } from './components/AfterShareContent' + +const StyledModalContent = ModalContent as React.FC +const StyledIconButton = IconButton as React.FC +const StyledFlex = Flex as React.FC + +export interface ShareAndReviewProps { + isOpen: boolean + onClose: () => void + onContinue?: () => void + onLeaveReview?: () => void +} + +export const ShareAndReviewModal = ({ + isOpen, + onClose, + onContinue, + onLeaveReview, +}: ShareAndReviewProps) => { + const [hasClickedLinkedin, setHasClickedLinkedin] = useState(false) + + // Resetear el estado cada vez que se abre o cierra la modal + useEffect(() => { + if (!isOpen) { + setHasClickedLinkedin(false) + } + }, [isOpen]) + + const handleLinkedinClick = () => { + // 1. Ejecutamos la acción original de LinkedIn (abrir la nueva pestaña) + if (onContinue) { + onContinue() + } + + // 2. Aplicamos un pequeño timeout (ej: 400ms) para reemplazar el botón por el texto + // Esto da tiempo a que se registre la acción antes de cambiar la UI visualmente + setTimeout(() => { + setHasClickedLinkedin(true) + }, 400) + } + + return ( + + + + + } + onClick={onClose} + variant="ghost" + size="sm" + h="auto" + minW="16px" + position="absolute" + top="16px" + right="16px" + _hover={{ + background: 'none', + }} + _focus={{ + boxShadow: 'none', + }} + _focusVisible={{ + boxShadow: `0 0 0 3px ${vars('colors-alert-deepSkyBlue')} inset`, + }} + /> + + + {!hasClickedLinkedin ? ( + + ) : ( + + )} + + + + ) +} diff --git a/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx b/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx new file mode 100644 index 000000000..2ba73183a --- /dev/null +++ b/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx @@ -0,0 +1,67 @@ +import { Text, TextProps, Flex, FlexProps, Image, ImageProps } from '@chakra-ui/react' + +import { BtnLink, BtnPrimary } from '@molecules' +import { vars } from '@theme' + +import { Star } from '@/atoms/Icons' + +const StyledImage = Image as React.FC +const StyledFlex = Flex as React.FC +const StyledText = Text as React.FC + +export interface AfterShareContentProps { + onClose: () => void + onLeaveReview?: () => void +} + +export const AfterShareContent = ({ onClose, onLeaveReview }: AfterShareContentProps) => { + return ( + + + + ¿Ya lo compartiste en LinkedIn? + + + Ahora cuéntanos qué tal fue aprender con nosotros. Tu opinión ayuda a otros + como tú a dar el primer paso. + + }> + Dejar mi opinión + + + Quizás más tarde + + + ) +} diff --git a/src/organisms/LinkedinAndReview/components/CustomCloseIcon.tsx b/src/organisms/LinkedinAndReview/components/CustomCloseIcon.tsx new file mode 100644 index 000000000..3ab7e5245 --- /dev/null +++ b/src/organisms/LinkedinAndReview/components/CustomCloseIcon.tsx @@ -0,0 +1,14 @@ +import { Base, BaseProps } from '@/atoms/Icons/Base' + +export function CustomCloseIcon(props: BaseProps): JSX.Element { + return ( + + + + ) +} diff --git a/src/organisms/LinkedinAndReview/components/InitialShareContent.tsx b/src/organisms/LinkedinAndReview/components/InitialShareContent.tsx new file mode 100644 index 000000000..07402f9c3 --- /dev/null +++ b/src/organisms/LinkedinAndReview/components/InitialShareContent.tsx @@ -0,0 +1,99 @@ +import { + Text, + TextProps, + Divider, + DividerProps, + Link, + LinkProps, + Flex, + FlexProps, + Image, + ImageProps, +} from '@chakra-ui/react' + +import { Star } from '@/atoms/Icons' +import { BtnPrimary } from '@/molecules' +import { vars } from '@theme' + +const StyledImage = Image as React.FC +const StyledFlex = Flex as React.FC +const StyledText = Text as React.FC +const StyledDivider = Divider as React.FC +const StyledLink = Link as React.FC + +interface InitialShareContentProps { + handleLinkedinClick: () => void + onLeaveReview?: () => void +} + +export const InitialShareContent = ({ + handleLinkedinClick, + onLeaveReview, +}: InitialShareContentProps) => { + return ( + <> + + + + + ¡Qué bueno que quieras compartirlo! + + + Aprobaste tu curso. Vamos a mostrarlo en tu LinkedIn. + + + + Continuar a LinkedIn + + + + + Ya que estás aquí + + + + + ¿Qué tal fue aprender con nosotros? + + + + + + Dejar mi opinión + + + + ) +} diff --git a/src/organisms/LinkedinAndReview/index.ts b/src/organisms/LinkedinAndReview/index.ts new file mode 100644 index 000000000..31b7ae25f --- /dev/null +++ b/src/organisms/LinkedinAndReview/index.ts @@ -0,0 +1 @@ +export { ShareAndReviewModal } from './ShareAndReviewModal' diff --git a/src/organisms/index.ts b/src/organisms/index.ts index 04530798e..abcc0204b 100644 --- a/src/organisms/index.ts +++ b/src/organisms/index.ts @@ -6,3 +6,4 @@ export * from './Resources' export * from './Calendar' export * from './Modals' export * from './User' +export * from './LinkedinAndReview' diff --git a/tsconfig.types.json b/tsconfig.types.json index 3416c0814..9d6b13ba3 100644 --- a/tsconfig.types.json +++ b/tsconfig.types.json @@ -7,6 +7,7 @@ "outDir": "dist" }, "include": [ - "src/index.ts" + "src/index.ts", + "src/vite-env.d.ts" ] } \ No newline at end of file From 41704daf899010b45edd36ad21ed96b491fa5a8f Mon Sep 17 00:00:00 2001 From: Javiera Munita Date: Thu, 30 Jul 2026 12:26:55 -0400 Subject: [PATCH 2/2] fix(PDYE-2075): types --- package-lock.json | 136 ++++-------------- .../LinkedinAndReview/ShareAndReviewModal.tsx | 4 +- .../components/AfterShareContent.tsx | 5 +- .../components/InitialShareContent.tsx | 2 +- 4 files changed, 38 insertions(+), 109 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54fcf118c..073deb7e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1570,40 +1570,6 @@ "strip-ansi": "^7.0.1" } }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -1613,23 +1579,6 @@ "ansi-regex": "^6.0.1" } }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - } - } - }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -1640,60 +1589,6 @@ "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } } } }, @@ -12584,6 +12479,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string.prototype.matchall": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", @@ -12672,6 +12578,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -13722,6 +13637,17 @@ "strip-ansi": "^6.0.0" } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx b/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx index d41e82181..1dd65f7a2 100644 --- a/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx +++ b/src/organisms/LinkedinAndReview/ShareAndReviewModal.tsx @@ -32,7 +32,7 @@ export const ShareAndReviewModal = ({ onClose, onContinue, onLeaveReview, -}: ShareAndReviewProps) => { +}: ShareAndReviewProps): JSX.Element => { const [hasClickedLinkedin, setHasClickedLinkedin] = useState(false) // Resetear el estado cada vez que se abre o cierra la modal @@ -42,7 +42,7 @@ export const ShareAndReviewModal = ({ } }, [isOpen]) - const handleLinkedinClick = () => { + const handleLinkedinClick: () => void = () => { // 1. Ejecutamos la acción original de LinkedIn (abrir la nueva pestaña) if (onContinue) { onContinue() diff --git a/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx b/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx index 2ba73183a..c389bffaa 100644 --- a/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx +++ b/src/organisms/LinkedinAndReview/components/AfterShareContent.tsx @@ -14,7 +14,10 @@ export interface AfterShareContentProps { onLeaveReview?: () => void } -export const AfterShareContent = ({ onClose, onLeaveReview }: AfterShareContentProps) => { +export const AfterShareContent = ({ + onClose, + onLeaveReview, +}: AfterShareContentProps): JSX.Element => { return ( { +}: InitialShareContentProps): JSX.Element => { return ( <>