Skip to content

Commit 49c72e9

Browse files
committed
posting to linkedin
1 parent e642eab commit 49c72e9

File tree

1 file changed

+131
-12
lines changed

1 file changed

+131
-12
lines changed

src/components/Certificate/index.tsx

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
useMediaQuery,
1111
useTheme,
1212
Divider,
13-
Link as MuiLink
13+
Link as MuiLink,
14+
Dialog,
15+
DialogTitle,
16+
DialogContent,
17+
DialogActions
1418
} from '@mui/material'
1519
import { useNavigate } from 'react-router-dom'
1620
import badge from '../../assets/images/badge.png'
@@ -148,6 +152,9 @@ const deriveDisplayNameFromAny = (value: any): string => {
148152
return utilGuess || asString
149153
}
150154

155+
// LinkedTrust LinkedIn organization ID for Add to Profile
156+
const LINKEDTRUST_LINKEDIN_ORG_ID = '69351143'
157+
151158
const Certificate: React.FC<CertificateProps> = ({
152159
issuer_name,
153160
subject,
@@ -178,6 +185,13 @@ const Certificate: React.FC<CertificateProps> = ({
178185
const [snackbarMessage, setSnackbarMessage] = useState('')
179186
const [currentUrl, setCurrentUrl] = useState('')
180187
const [isOwnerViaSameAs, setIsOwnerViaSameAs] = useState<boolean | null>(null)
188+
const [linkedInPreviewOpen, setLinkedInPreviewOpen] = useState(false)
189+
const [linkedInPreviewData, setLinkedInPreviewData] = useState<{
190+
name: string
191+
issueDate: string
192+
certUrl: string
193+
certId: string
194+
} | null>(null)
181195

182196
useEffect(() => {
183197
setCurrentUrl(window.location.href)
@@ -273,24 +287,88 @@ const Certificate: React.FC<CertificateProps> = ({
273287
}
274288
}
275289

276-
const generateLinkedInShareUrl = (credentialName: string, url: string) => {
277-
const encodedUrl = encodeURIComponent(url)
278-
const message = encodeURIComponent(
279-
`Excited to share my verified ${credentialName} credential from LinkedTrust! Check it out here: ${url} Thanks to my validators for confirming my skills!`
280-
)
281-
return `https://www.linkedin.com/feed/?shareActive=true&shareUrl=${encodedUrl}&text=${message}`
290+
const generateLinkedInAddToProfileUrl = () => {
291+
// Build LinkedIn Add to Profile URL for certifications
292+
const params = new URLSearchParams()
293+
params.set('startTask', 'CERTIFICATION_NAME')
294+
295+
// Build certificate name: claim : aspect : statement[0:50]
296+
const claimObj = claim as any
297+
const parts: string[] = []
298+
299+
if (claimObj?.claim) {
300+
parts.push(claimObj.claim)
301+
}
302+
if (claimObj?.aspect) {
303+
parts.push(claimObj.aspect)
304+
}
305+
if (statement) {
306+
const truncated = statement.length > 50 ? statement.substring(0, 50) + '...' : statement
307+
parts.push(truncated)
308+
}
309+
310+
const certName = parts.length > 0 ? parts.join(': ') : 'LinkedTrust Credential'
311+
params.set('name', certName)
312+
313+
// Organization (using ID pulls logo from LinkedIn company page)
314+
params.set('organizationId', LINKEDTRUST_LINKEDIN_ORG_ID)
315+
316+
// Issue date from effectiveDate
317+
if (effectiveDate) {
318+
const date = new Date(effectiveDate)
319+
params.set('issueYear', date.getFullYear().toString())
320+
params.set('issueMonth', (date.getMonth() + 1).toString())
321+
}
322+
323+
// Certificate ID and URL
324+
if (claimId) {
325+
params.set('certId', claimId.toString())
326+
}
327+
params.set('certUrl', currentUrl)
328+
329+
return `https://www.linkedin.com/profile/add?${params.toString()}`
282330
}
283331

284332
const handleLinkedInPost = () => {
285-
let credentialName = 'a new'
286-
if (subject && typeof subject === 'string' && !subject.includes('http')) {
287-
credentialName = subject
333+
// Show preview dialog first
334+
const claimObj = claim as any
335+
const parts: string[] = []
336+
337+
if (claimObj?.claim) {
338+
parts.push(claimObj.claim)
339+
}
340+
if (claimObj?.aspect) {
341+
parts.push(claimObj.aspect)
288342
}
289-
const linkedInShareUrl = generateLinkedInShareUrl(credentialName, currentUrl)
290-
window.open(linkedInShareUrl, '_blank')
343+
if (statement) {
344+
const truncated = statement.length > 50 ? statement.substring(0, 50) + '...' : statement
345+
parts.push(truncated)
346+
}
347+
348+
const certName = parts.length > 0 ? parts.join(': ') : 'LinkedTrust Credential'
349+
350+
let issueDate = ''
351+
if (effectiveDate) {
352+
const date = new Date(effectiveDate)
353+
issueDate = date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })
354+
}
355+
356+
setLinkedInPreviewData({
357+
name: certName,
358+
issueDate,
359+
certUrl: currentUrl,
360+
certId: claimId?.toString() || ''
361+
})
362+
setLinkedInPreviewOpen(true)
291363
handleClose()
292364
}
293365

366+
const handleLinkedInConfirm = () => {
367+
const linkedInUrl = generateLinkedInAddToProfileUrl()
368+
window.open(linkedInUrl, '_blank')
369+
setLinkedInPreviewOpen(false)
370+
}
371+
294372
const handleThisIsMe = async () => {
295373
if (!userUri || !subject) return
296374

@@ -751,6 +829,47 @@ const Certificate: React.FC<CertificateProps> = ({
751829
onClose={handleClaimDialogClose}
752830
validation={selectedValidation}
753831
/>
832+
833+
{/* LinkedIn Add to Profile Preview Dialog */}
834+
<Dialog
835+
open={linkedInPreviewOpen}
836+
onClose={() => setLinkedInPreviewOpen(false)}
837+
maxWidth="sm"
838+
fullWidth
839+
>
840+
<DialogTitle>Add Certificate to LinkedIn</DialogTitle>
841+
<DialogContent>
842+
<Typography variant="body2" color="textSecondary" sx={{ mb: 2 }}>
843+
This will open LinkedIn to add the following certificate to your profile:
844+
</Typography>
845+
<Box sx={{ bgcolor: 'grey.100', p: 2, borderRadius: 1 }}>
846+
<Typography variant="subtitle2" color="textSecondary">Name</Typography>
847+
<Typography variant="body1" sx={{ mb: 1.5 }}>{linkedInPreviewData?.name}</Typography>
848+
849+
<Typography variant="subtitle2" color="textSecondary">Issuing Organization</Typography>
850+
<Typography variant="body1" sx={{ mb: 1.5 }}>LinkedTrust</Typography>
851+
852+
{linkedInPreviewData?.issueDate && (
853+
<>
854+
<Typography variant="subtitle2" color="textSecondary">Issue Date</Typography>
855+
<Typography variant="body1" sx={{ mb: 1.5 }}>{linkedInPreviewData.issueDate}</Typography>
856+
</>
857+
)}
858+
859+
<Typography variant="subtitle2" color="textSecondary">Credential ID</Typography>
860+
<Typography variant="body1" sx={{ mb: 1.5 }}>{linkedInPreviewData?.certId}</Typography>
861+
862+
<Typography variant="subtitle2" color="textSecondary">Credential URL</Typography>
863+
<Typography variant="body1" sx={{ wordBreak: 'break-all' }}>{linkedInPreviewData?.certUrl}</Typography>
864+
</Box>
865+
</DialogContent>
866+
<DialogActions>
867+
<Button onClick={() => setLinkedInPreviewOpen(false)}>Cancel</Button>
868+
<Button onClick={handleLinkedInConfirm} variant="contained" color="primary">
869+
Add to LinkedIn
870+
</Button>
871+
</DialogActions>
872+
</Dialog>
754873
</Card>
755874
</Container>
756875
)

0 commit comments

Comments
 (0)