kyd-shared-badge 0.3.63 → 0.3.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/SharedBadgeDisplay.tsx +1 -1
- package/src/components/ResumeView.tsx +7 -4
- package/src/components/charts/ChartEmptyState.tsx +34 -0
- package/src/components/charts/ChartLegend.tsx +19 -0
- package/src/components/charts/ChartTooltip.tsx +80 -0
- package/src/components/spinner.tsx +12 -0
- package/src/index.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kyd-shared-badge",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.65",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"module": "./src/index.ts",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@chatscope/chat-ui-kit-styles": "^1.4.0",
|
|
24
24
|
"ai": "5.0.47",
|
|
25
25
|
"i18n-iso-countries": "^7.14.0",
|
|
26
|
+
"next-auth": "^4.24.11",
|
|
26
27
|
"react-hot-toast": "^2.6.0",
|
|
27
28
|
"react-icons": "^5.5.0",
|
|
28
29
|
"recharts": "^2.15.4",
|
|
@@ -348,7 +348,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
348
348
|
resume={resumeJson}
|
|
349
349
|
roleName={roleName}
|
|
350
350
|
badgeId={badgeId}
|
|
351
|
-
isPublic={
|
|
351
|
+
isPublic={badgeData.isPublic}
|
|
352
352
|
showDownloadButton={true}
|
|
353
353
|
/>
|
|
354
354
|
</div>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Spinner } from './spinner';
|
|
5
|
+
import { useSession } from 'next-auth/react';
|
|
4
6
|
|
|
5
7
|
type ResumeJSON = Partial<{
|
|
6
8
|
header: Partial<{ name: string; title: string; contact: Partial<{ email: string; phone: string; location: string; links: string[] }> }>;
|
|
@@ -18,7 +20,6 @@ interface ResumeViewProps {
|
|
|
18
20
|
roleName?: string;
|
|
19
21
|
badgeId?: string;
|
|
20
22
|
isPublic?: boolean;
|
|
21
|
-
idToken?: string;
|
|
22
23
|
showDownloadButton?: boolean;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -38,8 +39,9 @@ const Row = ({ label, value }: { label: string; value?: string }) => {
|
|
|
38
39
|
);
|
|
39
40
|
};
|
|
40
41
|
|
|
41
|
-
export default function ResumeView({ resume, roleName, badgeId, isPublic,
|
|
42
|
+
export default function ResumeView({ resume, roleName, badgeId, isPublic, showDownloadButton }: ResumeViewProps) {
|
|
42
43
|
const [isDownloading, setIsDownloading] = useState(false);
|
|
44
|
+
const { data: session } = useSession();
|
|
43
45
|
|
|
44
46
|
const header = resume?.header || {};
|
|
45
47
|
const contact = header?.contact || {} as any;
|
|
@@ -59,6 +61,7 @@ export default function ResumeView({ resume, roleName, badgeId, isPublic, idToke
|
|
|
59
61
|
const apiGatewayUrl = process.env.NEXT_PUBLIC_API_GATEWAY_URL;
|
|
60
62
|
if (!apiGatewayUrl) throw new Error('API not configured');
|
|
61
63
|
const usePublic = !!isPublic;
|
|
64
|
+
const idToken = (session as any)?.id_token;
|
|
62
65
|
const path = usePublic ? `/share/badge/${badgeId}/resume` : `/user/assessment/${badgeId}/resume`;
|
|
63
66
|
const res = await fetch(`${apiGatewayUrl}${path}`, {
|
|
64
67
|
method: 'GET',
|
|
@@ -98,7 +101,7 @@ export default function ResumeView({ resume, roleName, badgeId, isPublic, idToke
|
|
|
98
101
|
className={'px-3 py-2 text-sm rounded-md border'}
|
|
99
102
|
style={{ borderColor: 'var(--icon-button-secondary)', color: 'var(--text-main)', background: 'var(--content-card-background)' }}
|
|
100
103
|
>
|
|
101
|
-
{isDownloading ?
|
|
104
|
+
{isDownloading ? <Spinner /> : 'Download Resume (.docx)'}
|
|
102
105
|
</button>
|
|
103
106
|
) : null}
|
|
104
107
|
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export default function ChartEmptyState({ message }: { message: string }) {
|
|
6
|
+
// const width = 640
|
|
7
|
+
// const height = 180
|
|
8
|
+
// const padding = 28
|
|
9
|
+
// const gridColor = 'var(--icon-button-secondary)'
|
|
10
|
+
// const lineColor = 'var(--icon-button-secondary)'
|
|
11
|
+
// const areaColor = '#9CA3AF' // neutral-400-ish
|
|
12
|
+
|
|
13
|
+
// // A simple placeholder path
|
|
14
|
+
// const path = `M ${padding} ${height - padding - 20}
|
|
15
|
+
// C ${padding + 80} ${height - padding - 60},
|
|
16
|
+
// ${padding + 160} ${height - padding - 10},
|
|
17
|
+
// ${padding + 240} ${height - padding - 50}
|
|
18
|
+
// S ${padding + 400} ${height - padding - 30},
|
|
19
|
+
// ${width - padding} ${height - padding - 70}
|
|
20
|
+
// L ${width - padding} ${height - padding}
|
|
21
|
+
// L ${padding} ${height - padding} Z`
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="h-44 relative">
|
|
25
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
26
|
+
<div className="px-3 py-1.5 rounded-md border sm:text-sm text-xs" style={{ background: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)', color: 'var(--text-secondary)'}}>
|
|
27
|
+
{message}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export default function ChartLegend({ items }: { items: Array<{ label: string; color: string }> }) {
|
|
6
|
+
if (!items?.length) return null
|
|
7
|
+
return (
|
|
8
|
+
<div className="flex flex-wrap gap-x-3 gap-y-1 text-xs mb-2" style={{ color: 'var(--text-secondary)'}}>
|
|
9
|
+
{items.map((it) => (
|
|
10
|
+
<div key={it.label} className="flex items-center gap-1.5">
|
|
11
|
+
<span className="inline-block w-2.5 h-2.5 rounded-sm" style={{ backgroundColor: it.color }} />
|
|
12
|
+
<span>{it.label}</span>
|
|
13
|
+
</div>
|
|
14
|
+
))}
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
// type PayloadItem = {
|
|
6
|
+
// color?: string
|
|
7
|
+
// name?: string | number
|
|
8
|
+
// value?: number | string
|
|
9
|
+
// dataKey?: string
|
|
10
|
+
// }
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
export default function ChartTooltip(props: any) {
|
|
14
|
+
const {
|
|
15
|
+
active,
|
|
16
|
+
label,
|
|
17
|
+
payload,
|
|
18
|
+
title,
|
|
19
|
+
valueLabel,
|
|
20
|
+
valueSuffix,
|
|
21
|
+
valueFormatter,
|
|
22
|
+
labelFormatter,
|
|
23
|
+
} = props || {}
|
|
24
|
+
if (!active || !payload || !payload.length) return null
|
|
25
|
+
|
|
26
|
+
const fmtLabel = () => {
|
|
27
|
+
try {
|
|
28
|
+
if (labelFormatter) return labelFormatter(label)
|
|
29
|
+
return new Date(String(label)).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
|
|
30
|
+
} catch {
|
|
31
|
+
return String(label)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const fmtValue = (v: number | string) => {
|
|
36
|
+
const base = valueFormatter ? valueFormatter(v) : String(v)
|
|
37
|
+
return valueSuffix ? `${base}${valueSuffix}` : base
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
className="rounded-md border shadow-sm px-3 py-2 text-xs"
|
|
43
|
+
style={{
|
|
44
|
+
background: 'var(--content-card-background)',
|
|
45
|
+
borderColor: 'var(--icon-button-secondary)',
|
|
46
|
+
color: 'var(--text-main)'
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<div className="mb-1">
|
|
50
|
+
{title ? (
|
|
51
|
+
<div className="font-medium" style={{ color: 'var(--text-main)'}}>{title}</div>
|
|
52
|
+
) : null}
|
|
53
|
+
<div style={{ color: 'var(--text-secondary)' }}>{fmtLabel()}</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div className="space-y-1">
|
|
56
|
+
{payload.map((item: { color?: string, name?: string | number, value?: number | string, dataKey?: string }, idx: number) => (
|
|
57
|
+
<div key={idx} className="flex items-center justify-between gap-3">
|
|
58
|
+
<div className="flex items-center gap-2">
|
|
59
|
+
<span className="inline-block w-2.5 h-2.5 rounded-sm" style={{ backgroundColor: item.color || 'var(--icon-accent)' }} />
|
|
60
|
+
<span style={{ color: 'var(--text-secondary)'}}>{String(item.name || item.dataKey)}</span>
|
|
61
|
+
</div>
|
|
62
|
+
<div className="font-medium" style={{ color: 'var(--text-main)'}}>
|
|
63
|
+
{fmtValue(item.value ?? '')}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
{valueLabel && payload.length === 1 ? (
|
|
68
|
+
<div className="flex items-center justify-between gap-3">
|
|
69
|
+
<span style={{ color: 'var(--text-secondary)'}}>{valueLabel}</span>
|
|
70
|
+
<span className="font-medium" style={{ color: 'var(--text-main)'}}>
|
|
71
|
+
{fmtValue(payload[0].value ?? '')}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
) : null}
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
package/src/index.ts
CHANGED
|
@@ -4,4 +4,8 @@ export { default as PrintableBadgeDisplay } from './PrintableBadgeDisplay';
|
|
|
4
4
|
export { default as ChatWindowStreaming } from './chat/ChatWindowStreaming';
|
|
5
5
|
export { default as ChatWidget } from './chat/ChatWidget';
|
|
6
6
|
export * from './utils/date';
|
|
7
|
-
export { getBadgeImageUrl } from './components/ReportHeader';
|
|
7
|
+
export { getBadgeImageUrl } from './components/ReportHeader';
|
|
8
|
+
|
|
9
|
+
export * from './components/charts/ChartTooltip';
|
|
10
|
+
export * from './components/charts/ChartEmptyState';
|
|
11
|
+
export * from './components/charts/ChartLegend';
|