@betterinternship/components 2.4.4 → 2.5.1

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.
@@ -0,0 +1,9 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Button } from './button.js';
3
+
4
+ const FloatingActionButton = ({ onClick, children }) => {
5
+ return (jsx(Button, { onClick: onClick, className: "fixed bottom-4 right-4 z-50 rounded-full p-4 shadow-lg bg-primary text-white hover:bg-primary-dark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary", children: children }));
6
+ };
7
+
8
+ export { FloatingActionButton };
9
+ //# sourceMappingURL=fab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fab.js","sources":["../../../src/components/ui/fab.tsx"],"sourcesContent":["import { Button } from \"@/components/ui/button\";\r\n\r\nconst FloatingActionButton = ({ onClick, children }: { onClick: () => void; children: React.ReactNode }) => {\r\n return (\r\n <Button\r\n onClick={onClick}\r\n className=\"fixed bottom-4 right-4 z-50 rounded-full p-4 shadow-lg bg-primary text-white hover:bg-primary-dark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary\"\r\n >\r\n {children}\r\n </Button>\r\n );\r\n}\r\n\r\nexport { FloatingActionButton };\r\n"],"names":["_jsx"],"mappings":";;;AAEA,MAAM,oBAAoB,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAsD,KAAI;AACzG,IAAA,QACEA,GAAA,CAAC,MAAM,EAAA,EACL,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,2KAA2K,EAAA,QAAA,EAEpL,QAAQ,EAAA,CACF;AAEb;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/utils';\n\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\n return (\n <div\n data-slot=\"table-container\"\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\n >\n <table\n data-slot=\"table\"\n className={cn('w-full caption-bottom text-sm', className)}\n {...props}\n />\n </div>\n );\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn('[&_tr]:border-b', className)}\n {...props}\n />\n );\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\n return (\n <tbody\n data-slot=\"table-body\"\n className={cn('[&_tr:last-child]:border-0', className)}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn(\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\n return (\n <th\n data-slot=\"table-head\"\n className={cn(\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn(\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableCaption({\n className,\n ...props\n}: React.ComponentProps<'caption'>) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn('text-muted-foreground mt-4 text-sm', className)}\n {...props}\n />\n );\n}\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
1
+ {"version":3,"file":"table.js","sources":["../../../src/components/ui/table.tsx"],"sourcesContent":["import * as React from 'react';\r\n\r\nimport { cn } from '@/utils';\r\n\r\nfunction Table({ className, ...props }: React.ComponentProps<'table'>) {\r\n return (\r\n <div\r\n data-slot=\"table-container\"\r\n className=\"relative w-full overflow-x-auto [scrollbar-gutter:stable]\"\r\n >\r\n <table\r\n data-slot=\"table\"\r\n className={cn('w-full caption-bottom text-sm', className)}\r\n {...props}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\nfunction TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {\r\n return (\r\n <thead\r\n data-slot=\"table-header\"\r\n className={cn('[&_tr]:border-b', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {\r\n return (\r\n <tbody\r\n data-slot=\"table-body\"\r\n className={cn('[&_tr:last-child]:border-0', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {\r\n return (\r\n <tfoot\r\n data-slot=\"table-footer\"\r\n className={cn(\r\n 'bg-muted/50 border-t font-medium [&>tr]:last:border-b-0',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableRow({ className, ...props }: React.ComponentProps<'tr'>) {\r\n return (\r\n <tr\r\n data-slot=\"table-row\"\r\n className={cn(\r\n 'hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableHead({ className, ...props }: React.ComponentProps<'th'>) {\r\n return (\r\n <th\r\n data-slot=\"table-head\"\r\n className={cn(\r\n 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCell({ className, ...props }: React.ComponentProps<'td'>) {\r\n return (\r\n <td\r\n data-slot=\"table-cell\"\r\n className={cn(\r\n 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',\r\n className,\r\n )}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction TableCaption({\r\n className,\r\n ...props\r\n}: React.ComponentProps<'caption'>) {\r\n return (\r\n <caption\r\n data-slot=\"table-caption\"\r\n className={cn('text-muted-foreground mt-4 text-sm', className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nexport {\r\n Table,\r\n TableHeader,\r\n TableBody,\r\n TableFooter,\r\n TableHead,\r\n TableRow,\r\n TableCell,\r\n TableCaption,\r\n};\r\n"],"names":["_jsx"],"mappings":";;;AAIA,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;IACnE,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,WAAA,EACY,iBAAiB,EAC3B,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAErEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,OAAO,EACjB,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,EAAA,CACT,EAAA,CACE;AAEV;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAAA,GACvC,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACvE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,EAAA,GAClD,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAiC,EAAA;AACzE,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EAAA,WAAA,EACY,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,yDAAyD,EACzD,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACnE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,6EAA6E,EAC7E,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,oJAAoJ,EACpJ,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA8B,EAAA;AACpE,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EAAA,WAAA,EACY,YAAY,EACtB,SAAS,EAAE,EAAE,CACX,wGAAwG,EACxG,SAAS,CACV,EAAA,GACG,KAAK,EAAA,CACT;AAEN;AAEA,SAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACwB,EAAA;AAChC,IAAA,QACEA,GAAA,CAAA,SAAA,EAAA,EAAA,WAAA,EACY,eAAe,EACzB,SAAS,EAAE,EAAE,CAAC,oCAAoC,EAAE,SAAS,CAAC,EAAA,GAC1D,KAAK,EAAA,CACT;AAEN;;;;"}
@@ -0,0 +1,58 @@
1
+ export type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';
2
+ export interface MQJob<T = unknown> {
3
+ id: string;
4
+ type: string;
5
+ status: MQJobStatus;
6
+ progress?: {
7
+ total: number;
8
+ done: number;
9
+ failed: number;
10
+ };
11
+ result?: T;
12
+ error?: string;
13
+ }
14
+ interface MQJobsConfig {
15
+ /**
16
+ * Fetches the current state of a job. The package knows no URL and no
17
+ * response envelope — the consuming app owns both (plan §5.2). Reject/throw
18
+ * on a transport or not-found failure; React Query's own retry handles it.
19
+ */
20
+ poll: (jobId: string) => Promise<MQJob>;
21
+ }
22
+ /** Mount once near the root, alongside the app's other data providers. */
23
+ export declare const MQJobsProvider: ({ poll, children, }: MQJobsConfig & {
24
+ children: React.ReactNode;
25
+ }) => import("react/jsx-runtime").JSX.Element;
26
+ /**
27
+ * Polls a single `internal.mq_jobs` row to completion. Replaces
28
+ * `useClientProcess` for anything queued through the broker: no
29
+ * callback-URL dance, the result comes back inline on the job itself once
30
+ * `status` is terminal.
31
+ */
32
+ export declare function useMQJob<T = unknown>(jobId?: string | null): {
33
+ job: MQJob<T> | undefined;
34
+ status: MQJobStatus | undefined;
35
+ result: T | undefined;
36
+ error: string | undefined;
37
+ isPending: boolean;
38
+ isDone: boolean;
39
+ isFailed: boolean;
40
+ };
41
+ /**
42
+ * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a
43
+ * feature that can have several jobs in flight at once (e.g. a list of
44
+ * pending/handled items). Built on `useQueries` directly rather than
45
+ * composing `useMQJob` in a loop, since the number of tracked ids changes
46
+ * over time and that would violate the rules of hooks.
47
+ */
48
+ export declare function useMQJobs<T = unknown>(jobIds: readonly string[]): {
49
+ job: MQJob<T> | undefined;
50
+ status: MQJobStatus | undefined;
51
+ result: T | undefined;
52
+ error: string | undefined;
53
+ isPending: boolean;
54
+ isDone: boolean;
55
+ isFailed: boolean;
56
+ jobId: string;
57
+ }[];
58
+ export {};
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { createContext, useRef, useContext } from 'react';
4
+ import { useQuery, useQueries } from '@tanstack/react-query';
5
+
6
+ const MQJobsContext = createContext(null);
7
+ /** Mount once near the root, alongside the app's other data providers. */
8
+ const MQJobsProvider = ({ poll, children, }) => (jsx(MQJobsContext.Provider, { value: { poll }, children: children }));
9
+ const useMQJobsConfig = (caller) => {
10
+ const ctx = useContext(MQJobsContext);
11
+ if (!ctx)
12
+ throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);
13
+ return ctx;
14
+ };
15
+ const BASE_INTERVAL_MS = 2000;
16
+ const MAX_INTERVAL_MS = 10000;
17
+ /** Capped backoff keyed per job id, so each job restarts its own count. */
18
+ const nextInterval = (attempts, key, status) => {
19
+ if (status === 'done' || status === 'failed')
20
+ return false;
21
+ const attempt = attempts.current[key] ?? 0;
22
+ attempts.current[key] = attempt + 1;
23
+ return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);
24
+ };
25
+ const summarize = (job) => ({
26
+ job,
27
+ status: job?.status,
28
+ result: job?.result,
29
+ error: job?.error,
30
+ isPending: !job || job.status === 'queued' || job.status === 'processing',
31
+ isDone: job?.status === 'done',
32
+ isFailed: job?.status === 'failed',
33
+ });
34
+ /**
35
+ * Polls a single `internal.mq_jobs` row to completion. Replaces
36
+ * `useClientProcess` for anything queued through the broker: no
37
+ * callback-URL dance, the result comes back inline on the job itself once
38
+ * `status` is terminal.
39
+ */
40
+ function useMQJob(jobId) {
41
+ const { poll } = useMQJobsConfig('useMQJob');
42
+ const attempts = useRef({});
43
+ const query = useQuery({
44
+ queryKey: ['.__mq_job', jobId],
45
+ // `poll`'s result field is caller-typed via `T`; the transport itself
46
+ // doesn't know or care what shape a given job's result has.
47
+ queryFn: () => poll(jobId),
48
+ enabled: !!jobId,
49
+ staleTime: Infinity,
50
+ refetchOnWindowFocus: true,
51
+ refetchIntervalInBackground: true,
52
+ refetchInterval: (query) => nextInterval(attempts, jobId ?? '', query.state.data?.status),
53
+ });
54
+ return summarize(query.data);
55
+ }
56
+ /**
57
+ * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a
58
+ * feature that can have several jobs in flight at once (e.g. a list of
59
+ * pending/handled items). Built on `useQueries` directly rather than
60
+ * composing `useMQJob` in a loop, since the number of tracked ids changes
61
+ * over time and that would violate the rules of hooks.
62
+ */
63
+ function useMQJobs(jobIds) {
64
+ const { poll } = useMQJobsConfig('useMQJobs');
65
+ const attempts = useRef({});
66
+ const queries = useQueries({
67
+ queries: jobIds.map((jobId) => ({
68
+ queryKey: ['.__mq_job', jobId],
69
+ queryFn: () => poll(jobId),
70
+ staleTime: Infinity,
71
+ refetchOnWindowFocus: true,
72
+ refetchIntervalInBackground: true,
73
+ refetchInterval: (query) => nextInterval(attempts, jobId, query.state.data?.status),
74
+ })),
75
+ });
76
+ return jobIds.map((jobId, index) => ({
77
+ jobId,
78
+ ...summarize(queries[index]?.data),
79
+ }));
80
+ }
81
+
82
+ export { MQJobsProvider, useMQJob, useMQJobs };
83
+ //# sourceMappingURL=useMQJob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMQJob.js","sources":["../../src/hooks/useMQJob.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { createContext, useContext, useRef } from 'react';\r\nimport { useQueries, useQuery, Query } from '@tanstack/react-query';\r\n\r\nexport type MQJobStatus = 'queued' | 'processing' | 'done' | 'failed';\r\n\r\nexport interface MQJob<T = unknown> {\r\n id: string;\r\n type: string;\r\n status: MQJobStatus;\r\n progress?: { total: number; done: number; failed: number };\r\n result?: T;\r\n error?: string;\r\n}\r\n\r\ninterface MQJobsConfig {\r\n /**\r\n * Fetches the current state of a job. The package knows no URL and no\r\n * response envelope — the consuming app owns both (plan §5.2). Reject/throw\r\n * on a transport or not-found failure; React Query's own retry handles it.\r\n */\r\n poll: (jobId: string) => Promise<MQJob>;\r\n}\r\n\r\nconst MQJobsContext = createContext<MQJobsConfig | null>(null);\r\n\r\n/** Mount once near the root, alongside the app's other data providers. */\r\nexport const MQJobsProvider = ({\r\n poll,\r\n children,\r\n}: MQJobsConfig & { children: React.ReactNode }) => (\r\n <MQJobsContext.Provider value={{ poll }}>{children}</MQJobsContext.Provider>\r\n);\r\n\r\nconst useMQJobsConfig = (caller: string): MQJobsConfig => {\r\n const ctx = useContext(MQJobsContext);\r\n if (!ctx)\r\n throw new Error(`${caller}() must be used within a <MQJobsProvider>.`);\r\n return ctx;\r\n};\r\n\r\nconst BASE_INTERVAL_MS = 2000;\r\nconst MAX_INTERVAL_MS = 10000;\r\n\r\n/** Capped backoff keyed per job id, so each job restarts its own count. */\r\nconst nextInterval = (\r\n attempts: { current: Record<string, number> },\r\n key: string,\r\n status: MQJobStatus | undefined,\r\n): number | false => {\r\n if (status === 'done' || status === 'failed') return false;\r\n const attempt = attempts.current[key] ?? 0;\r\n attempts.current[key] = attempt + 1;\r\n return Math.min(BASE_INTERVAL_MS * 1.5 ** attempt, MAX_INTERVAL_MS);\r\n};\r\n\r\nconst summarize = <T,>(job: MQJob<T> | undefined) => ({\r\n job,\r\n status: job?.status,\r\n result: job?.result,\r\n error: job?.error,\r\n isPending: !job || job.status === 'queued' || job.status === 'processing',\r\n isDone: job?.status === 'done',\r\n isFailed: job?.status === 'failed',\r\n});\r\n\r\n/**\r\n * Polls a single `internal.mq_jobs` row to completion. Replaces\r\n * `useClientProcess` for anything queued through the broker: no\r\n * callback-URL dance, the result comes back inline on the job itself once\r\n * `status` is terminal.\r\n */\r\nexport function useMQJob<T = unknown>(jobId?: string | null) {\r\n const { poll } = useMQJobsConfig('useMQJob');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const query = useQuery<MQJob<T>>({\r\n queryKey: ['.__mq_job', jobId],\r\n // `poll`'s result field is caller-typed via `T`; the transport itself\r\n // doesn't know or care what shape a given job's result has.\r\n queryFn: () => poll(jobId as string) as Promise<MQJob<T>>,\r\n enabled: !!jobId,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId ?? '', query.state.data?.status),\r\n });\r\n\r\n return summarize(query.data);\r\n}\r\n\r\n/**\r\n * Polls a dynamic set of `internal.mq_jobs` rows to completion — for a\r\n * feature that can have several jobs in flight at once (e.g. a list of\r\n * pending/handled items). Built on `useQueries` directly rather than\r\n * composing `useMQJob` in a loop, since the number of tracked ids changes\r\n * over time and that would violate the rules of hooks.\r\n */\r\nexport function useMQJobs<T = unknown>(jobIds: readonly string[]) {\r\n const { poll } = useMQJobsConfig('useMQJobs');\r\n const attempts = useRef<Record<string, number>>({});\r\n\r\n const queries = useQueries({\r\n queries: jobIds.map((jobId) => ({\r\n queryKey: ['.__mq_job', jobId],\r\n queryFn: () => poll(jobId) as Promise<MQJob<T>>,\r\n staleTime: Infinity,\r\n refetchOnWindowFocus: true,\r\n refetchIntervalInBackground: true,\r\n refetchInterval: (query: Query<MQJob<T>>) =>\r\n nextInterval(attempts, jobId, query.state.data?.status),\r\n })),\r\n });\r\n\r\n return jobIds.map((jobId, index) => ({\r\n jobId,\r\n ...summarize(queries[index]?.data as MQJob<T> | undefined),\r\n }));\r\n}\r\n"],"names":[],"mappings":";;;;;AAyBA;AAEA;AACO;AAOP;AACE;AACA;AACE;AACF;AACF;AAEA;AACA;AAEA;AACA;AAKE;AAA8C;;;AAG9C;AACF;AAEA;;;;;AAKE;AACA;AACA;AACD;AAED;;;;;AAKG;AACG;;AAEJ;;AAGE;;;AAGA;;AAEA;AACA;AACA;;AAGD;AAED;AACF;AAEA;;;;;;AAMG;AACG;;AAEJ;;;AAII;AACA;AACA;AACA;AACA;AACA;AAED;AACF;;;;AAKA;AACH;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './config';
2
2
  export * from './utils';
3
3
  export * from './hooks/useClientProcess';
4
+ export * from './hooks/useMQJob';
4
5
  export * from './components/ui/button';
5
6
  export * from './components/ui/accordion';
6
7
  export * from './components/ui/app-header';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { config, configure } from './config.js';
2
2
  export { cn } from './utils.js';
3
3
  export { ClientProcessesProvider, useClientProcess } from './hooks/useClientProcess.js';
4
+ export { MQJobsProvider, useMQJob, useMQJobs } from './hooks/useMQJob.js';
4
5
  export { Button, buttonVariants } from './components/ui/button.js';
5
6
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './components/ui/accordion.js';
6
7
  export { AppHeader } from './components/ui/app-header.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@betterinternship/components",
3
- "version": "2.4.4",
3
+ "version": "2.5.1",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,22 +27,6 @@
27
27
  "import": "./dist/components/ui/accordion.js",
28
28
  "types": "./dist/components/ui/accordion.d.ts"
29
29
  },
30
- "./app-header": {
31
- "import": "./dist/components/ui/app-header.js",
32
- "types": "./dist/components/ui/app-header.d.ts"
33
- },
34
- "./dropdown-menu": {
35
- "import": "./dist/components/ui/dropdown-menu.js",
36
- "types": "./dist/components/ui/dropdown-menu.d.ts"
37
- },
38
- "./page-header": {
39
- "import": "./dist/components/ui/page-header.js",
40
- "types": "./dist/components/ui/page-header.d.ts"
41
- },
42
- "./status-notice": {
43
- "import": "./dist/components/ui/status-notice.js",
44
- "types": "./dist/components/ui/status-notice.d.ts"
45
- },
46
30
  "./calendar": {
47
31
  "import": "./dist/components/ui/calendar.js",
48
32
  "types": "./dist/components/ui/calendar.d.ts"
@@ -107,6 +91,22 @@
107
91
  "import": "./dist/components/ui/tooltip.js",
108
92
  "types": "./dist/components/ui/tooltip.d.ts"
109
93
  },
94
+ "./page-header": {
95
+ "import": "./dist/components/ui/page-header.js",
96
+ "types": "./dist/components/ui/page-header.d.ts"
97
+ },
98
+ "./status-notice": {
99
+ "import": "./dist/components/ui/status-notice.js",
100
+ "types": "./dist/components/ui/status-notice.d.ts"
101
+ },
102
+ "./app-header": {
103
+ "import": "./dist/components/ui/app-header.js",
104
+ "types": "./dist/components/ui/app-header.d.ts"
105
+ },
106
+ "./dropdown-menu": {
107
+ "import": "./dist/components/ui/dropdown-menu.js",
108
+ "types": "./dist/components/ui/dropdown-menu.d.ts"
109
+ },
110
110
  "./theme.css": "./theme.css"
111
111
  },
112
112
  "repository": {