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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.3.63",
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={true}
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, useMemo } from 'react';
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, idToken, showDownloadButton }: ResumeViewProps) {
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 ? 'Preparing…' : 'Download Resume (.docx)'}
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
+
@@ -0,0 +1,12 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ export function Spinner() {
5
+ return (
6
+ <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-[var(--icon-accent-hover)]"></div>
7
+ )
8
+ }
9
+
10
+ export default Spinner
11
+
12
+
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';