@@ -9,17 +9,24 @@ import {
99 Menu ,
1010 MenuItem ,
1111 IconButton ,
12+ Dialog ,
13+ DialogTitle ,
14+ DialogContent ,
15+ DialogActions ,
16+ Button ,
1217} from '@mui/material' ;
1318import { useEffect , useState } from 'react' ;
1419import settingImage from '../../../public/images/settings.png' ;
1520import Image from 'next/image' ;
1621import ChevronRightIcon from '@mui/icons-material/ChevronRight' ;
22+ import VisibilityIcon from '@mui/icons-material/Visibility' ;
1723import { useRouter } from 'next/navigation' ;
1824import { getUserDetails } from '@learner/utils/API/userService' ;
1925import { Loader , useTranslation } from '@shared-lib' ;
2026import { isUnderEighteen , toPascalCase } from '@learner/utils/helper' ;
2127import { fetchForm } from '@shared-lib-v2/DynamicForm/components/DynamicFormCallback' ;
2228import { FormContext } from '@shared-lib-v2/DynamicForm/components/DynamicFormConstant' ;
29+ import DocumentViewer from '@shared-lib-v2/DynamicForm/components/DocumentViewer/DocumentViewer' ;
2330
2431// Helper function to get field value from userData based on schema
2532const getFieldValue = ( fieldName : string , fieldSchema : Record < string , unknown > , userData : Record < string , unknown > , customFields : Array < Record < string , unknown > > = [ ] ) => {
@@ -104,6 +111,9 @@ const UserProfileCard = ({ maxWidth = '600px' }) => {
104111 const [ formSchema , setFormSchema ] = useState < Record < string , unknown > | null > ( null ) ; // Form schema state
105112 const { t } = useTranslation ( ) ;
106113 const [ anchorEl , setAnchorEl ] = useState < null | HTMLElement > ( null ) ;
114+ const [ previewUrl , setPreviewUrl ] = useState < string | null > ( null ) ;
115+ const [ isPreviewOpen , setIsPreviewOpen ] = useState ( false ) ;
116+ const [ previewTitle , setPreviewTitle ] = useState < string > ( '' ) ;
107117
108118 const storedConfig =
109119 typeof window !== 'undefined'
@@ -184,6 +194,39 @@ const UserProfileCard = ({ maxWidth = '600px' }) => {
184194 setAnchorEl ( null ) ;
185195 } ;
186196
197+ const handlePreview = ( url : string , title : string ) => {
198+ setPreviewUrl ( url ) ;
199+ setPreviewTitle ( title ) ;
200+ setIsPreviewOpen ( true ) ;
201+ } ;
202+
203+ const handleClosePreview = ( ) => {
204+ setIsPreviewOpen ( false ) ;
205+ setPreviewUrl ( null ) ;
206+ setPreviewTitle ( '' ) ;
207+ } ;
208+
209+ // Helper function to check if a field is a file field
210+ const isFileField = ( fieldSchema : Record < string , unknown > ) : boolean => {
211+ return (
212+ fieldSchema ?. field_type === 'file_upload' ||
213+ fieldSchema ?. field_type === 'file' ||
214+ fieldSchema ?. type === 'array' && ( fieldSchema ?. items as Record < string , unknown > ) ?. type === 'string' &&
215+ ( ( fieldSchema ?. items as Record < string , unknown > ) ?. format === 'data-url' || ( fieldSchema ?. items as Record < string , unknown > ) ?. format === 'uri' )
216+ ) ;
217+ } ;
218+
219+ // Helper function to check if a value is a valid URL
220+ const isValidUrl = ( value : unknown ) : boolean => {
221+ if ( typeof value !== 'string' ) return false ;
222+ try {
223+ const url = new URL ( value ) ;
224+ return url . protocol === 'http:' || url . protocol === 'https:' ;
225+ } catch {
226+ return false ;
227+ }
228+ } ;
229+
187230 const handleOpen = ( option : string ) => {
188231 console . log ( option ) ;
189232 if ( option === t ( 'LEARNER_APP.USER_PROFILE_CARD.EDIT_PROFILE' ) ) {
@@ -586,13 +629,46 @@ const UserProfileCard = ({ maxWidth = '600px' }) => {
586629 { otherSectionFields . map ( ( field ) => {
587630 const fieldTitle = ( field . schema . title as string ) || field . name ;
588631 const labelKey = `FORM.${ fieldTitle } ` ;
632+ const isFile = isFileField ( field . schema ) ;
633+ const hasValidUrl = isValidUrl ( field . rawValue ) ;
589634
590635 return (
591636 < Grid item xs = { 6 } key = { field . name } >
592637 < Typography sx = { labelStyle } >
593638 { t ( labelKey , { defaultValue : toPascalCase ( String ( fieldTitle ) . replace ( / _ / g, ' ' ) ) } ) }
594639 </ Typography >
595- < Typography sx = { valueStyle } > { t ( `FORM.${ String ( field . value ) . toUpperCase ( ) } ` , { defaultValue : toPascalCase ( String ( field . value ) ) } ) } </ Typography >
640+ { isFile && hasValidUrl ? (
641+ < Box
642+ sx = { {
643+ display : 'flex' ,
644+ alignItems : 'center' ,
645+ gap : 0.5 ,
646+ cursor : 'pointer' ,
647+ '&:hover' : {
648+ '& .view-text' : {
649+ textDecoration : 'underline' ,
650+ }
651+ }
652+ } }
653+ onClick = { ( ) => handlePreview ( String ( field . rawValue ) , fieldTitle ) }
654+ >
655+ < VisibilityIcon sx = { { fontSize : '1rem' , color : 'primary.main' } } />
656+ < Typography
657+ className = "view-text"
658+ sx = { {
659+ ...valueStyle ,
660+ color : 'primary.main' ,
661+ fontWeight : 500
662+ } }
663+ >
664+ { t ( 'VIEW_FILE' , { defaultValue : 'View File' } ) }
665+ </ Typography >
666+ </ Box >
667+ ) : (
668+ < Typography sx = { valueStyle } >
669+ { t ( `FORM.${ String ( field . value ) . toUpperCase ( ) } ` , { defaultValue : toPascalCase ( String ( field . value ) ) } ) }
670+ </ Typography >
671+ ) }
596672 </ Grid >
597673 ) ;
598674 } ) }
@@ -637,6 +713,56 @@ const UserProfileCard = ({ maxWidth = '600px' }) => {
637713 >
638714 Open PDF
639715 </a> */ }
716+
717+ { /* File Preview Dialog */ }
718+ < Dialog
719+ open = { isPreviewOpen }
720+ onClose = { handleClosePreview }
721+ maxWidth = "lg"
722+ fullWidth
723+ PaperProps = { {
724+ sx : {
725+ height : '90vh' ,
726+ maxHeight : '90vh' ,
727+ } ,
728+ } }
729+ >
730+ < DialogTitle >
731+ { t ( 'FILE_PREVIEW' , { defaultValue : 'File Preview' } ) } - { t ( `FORM.${ previewTitle } ` , { defaultValue : toPascalCase ( String ( previewTitle ) . replace ( / _ / g, ' ' ) ) } ) }
732+ </ DialogTitle >
733+ < DialogContent
734+ sx = { {
735+ p : 0 ,
736+ display : 'flex' ,
737+ flexDirection : 'column' ,
738+ overflow : 'hidden' ,
739+ } }
740+ >
741+ { previewUrl && (
742+ < DocumentViewer
743+ url = { previewUrl }
744+ width = "100%"
745+ height = "100%"
746+ showError = { true }
747+ showDownloadButton = { false }
748+ />
749+ ) }
750+ </ DialogContent >
751+ < DialogActions >
752+ < Button onClick = { handleClosePreview } > { t ( 'COMMON.CLOSE' , { defaultValue : 'Close' } ) } </ Button >
753+ { /* {previewUrl && (
754+ <Button
755+ variant="contained"
756+ href={previewUrl}
757+ download
758+ target="_blank"
759+ rel="noopener noreferrer"
760+ >
761+ {t('COMMON.DOWNLOAD', { defaultValue: 'Download' })}
762+ </Button> */ }
763+
764+ </ DialogActions >
765+ </ Dialog >
640766 </ Box >
641767 ) ;
642768} ;
0 commit comments