-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Open
Description
I am using a single component with dynamic data. When I select for example PDF (A) as my first PDF in dropdown and move to other PDFs it works fine. But when I select any other PDF and switch to PDF (A) it throws this error.
Also when I remove the arabic content through my getTranslation function it works fine. There is no data inconsistency issue from JSON.
IF I REMOVE ARABIC FONT IT WORKS FINE
Someone on this issue said #3050 (comment)
to use a different font it maybe a font issue but this is still happening
Code
Preview Component
import { useEffect, useState } from 'react'
import CertificatePDF from '../../../Certificates/CertificatePDF'
import { pdf } from '@react-pdf/renderer'
import { Document, Page, pdfjs } from 'react-pdf'
import classess from './BulkCertificate.module.scss'
import { useDebounce } from '../../../../hooks/useDebounce'
import Spinner from '../../../../components/shared/Spinner'
const CertificatePreview = ({
certificate,
setButtonDisable
}: {
certificate: ICertification
setButtonDisable: (value: boolean) => void
}) => {
const [pdfUrl, setPdfUrl] = useState<string | null>(null)
const [renderedCertificate, setRenderedCertificate] = useState<ICertification>(certificate)
pdfjs.GlobalWorkerOptions.workerSrc = `https://esm.sh/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`
const debouncedCertificateId = useDebounce(certificate?.id, 300)
useEffect(() => {
certificate?.id === debouncedCertificateId && setRenderedCertificate(certificate)
}, [debouncedCertificateId, certificate])
const generatePdf = async () => {
const blob = await pdf(
<CertificatePDF certificate={renderedCertificate} name='John Doe' alternativeName='فلان بن فلان' viewPDF />
).toBlob()
const objectUrl = URL.createObjectURL(blob)
setPdfUrl((prev) => {
if (prev) URL.revokeObjectURL(prev)
return objectUrl
})
}
useEffect(() => {
renderedCertificate?.id && generatePdf()
}, [renderedCertificate?.id, renderedCertificate?.certificateTemplate?.id])
useEffect(() => pdfUrl ? setButtonDisable(false) : setButtonDisable(true), [pdfUrl])
return (
<div className={classess.certificate_view} key={renderedCertificate?.certificateTemplate?.id}>
{pdfUrl ? (
<Document
file={pdfUrl}
loading={<div className={classess.dummy_loader_certificate}><Spinner size='small' /></div>}
>
<Page
pageNumber={1}
loading={<div className={classess.dummy_loader_certificate} />}
width={500}
height={250}
renderTextLayer={false}
renderAnnotationLayer={false}
/>
</Document>
) : (<div className={classess.dummy_loader_certificate}> <Spinner size='small'/></div>)}
</div>
)
}
export default CertificatePreview
import { Document, Page, Text, View, Image, StyleSheet } from '@react-pdf/renderer'
import { Font } from '@react-pdf/renderer'
import { formatToMonthDayYear } from '../../utils/helpers/string'
Font.register({
family: 'DINNextLTArabic',
src: '/fonts/DINNEXTLTARABIC-REGULAR.TTF',
fontWeight: 400
})
Font.register({
family: 'DINNextLTArabic',
src: '/fonts/DINNEXTLTARABIC-BOLD.TTF',
fontWeight: 700
})
type CertificatePDFProps = {
certificate: ICertification
user?: IUser
name?:string
alternativeName?:string
event?: IEvent
isEvent?: boolean
qrCodeSrc?: string
viewPDF?: boolean
}
const styles = StyleSheet.create({
page: {
fontFamily: 'DINNextLTArabic',
flexDirection: 'column',
alignItems: 'center',
backgroundColor: '#ffffff',
width: '100%',
height: '100%',
overflow: 'hidden'
},
logoContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 20,
width: '100%'
},
logo: {
width: 140,
height: 60,
marginBottom: 80,
paddingTop: 20,
paddingLeft: 35
},
bgImage: {
width: 250
},
title: {
fontFamily: 'DINNextLTArabic',
fontSize: 15,
fontWeight: 'bold',
width: '40%',
color: '#1f2937'
},
titleArabic: {
fontFamily: 'DINNextLTArabic',
fontSize: 13,
fontWeight: 'bold',
width: '40%',
color: '#1f2937',
textAlign: 'right'
},
subheading: {
fontFamily: 'DINNextLTArabic',
fontSize: 15,
marginBottom: 20,
textAlign: 'center'
},
certificateAchievementArabic: {
fontFamily: 'DINNextLTArabic',
fontSize: 24,
color: '#143861',
fontWeight: 'bold',
marginBottom: 60,
marginTop: -80,
textAlign: 'center'
},
certificateAchievementEnglish: {
fontFamily: 'DINNextLTArabic',
fontSize: 24,
color: '#143861',
fontWeight: 'bold',
marginBottom: 20,
marginTop: -40,
textAlign: 'center'
},
issuedTo: {
fontFamily: 'DINNextLTArabic',
fontSize: 24,
marginBottom: 10,
color: '#143861',
textAlign: 'center',
fontWeight: 'extrabold'
},
flexDescription: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: '90%'
},
center: {
flexDirection: 'row',
justifyContent: 'center'
},
details: {
fontFamily: 'DINNextLTArabic',
fontSize: 15,
marginBottom: 20,
textAlign: 'center',
color: '#1f2937',
position: 'relative'
},
details1: {
fontFamily: 'DINNextLTArabic',
fontSize: 15,
marginTop: 10,
textAlign: 'center',
color: '#1f2937'
},
dates: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
paddingHorizontal: 40,
color: 'gray'
},
dateItem: {
fontSize: 14
},
borderBottom: {
backgroundColor: '#143861',
width: '100%',
height: 25,
position: 'absolute',
bottom: 0
},
footer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
width: '90%'
},
stamp: {
width: '118',
height: '122'
},
signature: {
color: '#B0B0B0',
fontSize: 13
},
signatureBorder: {
width: '80%',
borderTop: '1px solid #B0B0B0',
height: '2',
textAlign: 'center'
},
signatureContainer: {
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
},
sign: {
width: '200px',
height: '90px',
marginBottom: '-20px'
},
footerMarginBottom: {
marginBottom: 25
},
qrCode: {
width: 100,
height: 100,
marginRight: 20
}
})
const CertificatePDF = ({ certificate, user, name, event, qrCodeSrc, viewPDF = false, alternativeName }: CertificatePDFProps) => {
type TranslationKey = 'heading' | 'authority' | 'leadStatement' | 'preTitle' | 'signature' | 'footer'
interface Translation {
locale: string
[key: string]: string | undefined
}
const isValidTranslation = (obj: unknown): obj is Translation => {
return (
typeof obj === 'object' &&
obj !== null &&
'locale' in obj &&
typeof (obj as Translation).locale === 'string'
)
}
const getTranslation = (key: TranslationKey, defaultValue: string, locale: string = 'en'): string => {
if (!certificate.certificateTemplateId && !viewPDF) return defaultValue
const translations = certificate?.certificateTemplate?.translations || []
const translation = translations.find(t =>
isValidTranslation(t) && t.locale === locale
) as Translation | undefined
return translation?.[key] ?? defaultValue
}
return (
<Document>
<Page style={styles.page} size={[550, 842]} orientation='landscape'>
<View style={styles.logoContainer}>
<Image style={styles.logo} src='/logos.png' />
{qrCodeSrc && <Image style={styles.qrCode} src={qrCodeSrc} />}
</View>
<Text style={styles.certificateAchievementArabic}>
{getTranslation('heading', 'شـــهــــــــادة اجـتيـــــــاز', 'ar')}
</Text>
<Text style={styles.certificateAchievementEnglish}>
{getTranslation('heading', 'Certificate of Achievement', 'en')}
</Text>
<View style={styles.flexDescription}>
<Text style={styles.subheading}>
{getTranslation('authority', 'Saudi Data and AI Authority (SDAIA) Certifies that', 'en')}
</Text>
<Text style={styles.subheading}>
{getTranslation('authority', 'تمنح الهيئة السعودية للبيانات والذكاء الاصطناعي (سدايا)', 'ar')}
</Text>
</View>
<View style={(alternativeName || user?.profile?.alternativeName) ? styles.flexDescription : styles.center}>
<Text style={styles.issuedTo}>{user?.profile?.name ?? name}</Text>
<Text style={styles.issuedTo}>{alternativeName ?? user?.profile?.alternativeName}</Text>
</View>
<View style={styles.flexDescription}>
<Text style={styles.details1}>
{getTranslation('leadStatement', 'Has Obtained the Certificate of Achievement for', 'en')}
</Text>
<Text style={styles.details1}>
{getTranslation('leadStatement', 'شــــــــــهــادة اجـــتـــــياز', 'ar')}
</Text>
</View>
<View style={styles.flexDescription}>
<Text style={styles.title}>
{getTranslation('preTitle', 'Professional Training Program in', 'en')}
{event?.translations?.find(item => item.locale === 'en')?.name ?? certificate?.certificationableTranslations?.find(item => item.locale === 'en')?.title ?? certificate?.certificationableTitle}
</Text>
<Text style={styles.titleArabic}>
{getTranslation('preTitle', 'البرنامج التدريبي الاحترافي في', 'ar')}
{event?.translations?.find(item => item.locale === 'ar')?.name ?? certificate?.certificationableTranslations?.find(item => item.locale === 'ar')?.title ?? certificate?.certificationableTitle}
</Text>
</View>
<View style={styles.flexDescription}>
<Text style={styles.details}>
Completion Date: {viewPDF ? 'DD/MM/YYYY' : formatToMonthDayYear(certificate.completionDate as string)}
</Text>
<Text style={styles.details}>
تاريخ الإنجاز: {viewPDF ? 'شهر/يوم/سنة' : formatToMonthDayYear(certificate.completionDate as string)}
</Text>
</View>
<View style={styles.footer}>
<View style={styles.signatureContainer}>
<Image style={styles.sign} src='/signature.png' />
<View style={styles.signatureBorder} />
<Text style={styles.signature}>
{getTranslation('footer', 'د أحمد عوض الغامدي | المشرف العام على قطاع بناء القدرات', 'ar')}
</Text>
<Text style={styles.signature}>
{getTranslation('footer', 'Dr. Ahmed Alghamdi | The Head of Capacity Building', 'en')}
</Text>
</View>
</View>
</Page>
</Document>
)
}
export default CertificatePDF
Metadata
Metadata
Assignees
Labels
No labels