@mohasinac/appkit 4.45.0 → 4.46.0

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.
Files changed (152) hide show
  1. package/dist/.build-stamp.json +4 -4
  2. package/dist/_internal/server/features/categories/live-counts.d.ts +41 -0
  3. package/dist/_internal/server/features/categories/live-counts.js +72 -0
  4. package/dist/_internal/server/features/checkout/expand-order-items.js +17 -0
  5. package/dist/_internal/server/features/orders/adapters.js +29 -0
  6. package/dist/_internal/server/features/parts/assembly.d.ts +126 -0
  7. package/dist/_internal/server/features/parts/assembly.js +246 -0
  8. package/dist/_internal/server/features/parts/data.d.ts +65 -0
  9. package/dist/_internal/server/features/parts/data.js +170 -0
  10. package/dist/_internal/server/features/parts/og.d.ts +34 -0
  11. package/dist/_internal/server/features/parts/og.js +66 -0
  12. package/dist/_internal/server/features/search/search-everything.d.ts +75 -0
  13. package/dist/_internal/server/features/search/search-everything.js +120 -0
  14. package/dist/_internal/server/features/search/search-sources.d.ts +17 -0
  15. package/dist/_internal/server/features/search/search-sources.js +138 -0
  16. package/dist/_internal/server/jobs/core/categoryTaxonomyBackfill.d.ts +70 -0
  17. package/dist/_internal/server/jobs/core/categoryTaxonomyBackfill.js +302 -0
  18. package/dist/_internal/server/jobs/core/countersReconcile.js +128 -19
  19. package/dist/_internal/server/jobs/core/jobRunners.js +12 -0
  20. package/dist/_internal/server/jobs/core/onCategoryWrite.js +73 -3
  21. package/dist/_internal/server/jobs/core/onProductWrite.js +93 -43
  22. package/dist/_internal/server/jobs/core/productViewWindows.d.ts +2 -0
  23. package/dist/_internal/server/jobs/core/productViewWindows.js +173 -0
  24. package/dist/_internal/server/jobs/core/testDataCleanup.d.ts +1 -1
  25. package/dist/_internal/server/jobs/core/testDataCleanup.js +27 -1
  26. package/dist/_internal/server/jobs/handlers/pageViewRollup.d.ts +20 -0
  27. package/dist/_internal/server/jobs/handlers/pageViewRollup.js +25 -1
  28. package/dist/_internal/shared/actions/action-registry.js +36 -0
  29. package/dist/_internal/shared/features/promotions/schema.d.ts +2 -2
  30. package/dist/_internal/shared/features/shipping/protections.d.ts +93 -1
  31. package/dist/_internal/shared/features/shipping/protections.js +127 -0
  32. package/dist/_internal/shared/search/part-aliases.d.ts +44 -0
  33. package/dist/_internal/shared/search/part-aliases.js +104 -0
  34. package/dist/constants/api-endpoints.d.ts +18 -12
  35. package/dist/constants/api-endpoints.js +6 -8
  36. package/dist/constants/field-names.d.ts +0 -2
  37. package/dist/constants/field-names.js +0 -2
  38. package/dist/constants/index.d.ts +1 -1
  39. package/dist/constants/index.js +1 -1
  40. package/dist/core/index.d.ts +0 -3
  41. package/dist/core/index.js +0 -2
  42. package/dist/errors/messages.d.ts +0 -7
  43. package/dist/errors/messages.js +0 -8
  44. package/dist/features/admin/components/AdminSectionsView.js +83 -32
  45. package/dist/features/admin/components/AdminSiteSettingsView.js +6 -2
  46. package/dist/features/admin/components/sections/sectionTemplates.d.ts +117 -0
  47. package/dist/features/admin/components/sections/sectionTemplates.js +213 -0
  48. package/dist/features/admin/schemas/firestore.d.ts +15 -0
  49. package/dist/features/admin/types/index.d.ts +0 -1
  50. package/dist/features/auth/permissions/constants.d.ts +1 -1
  51. package/dist/features/auth/permissions/constants.js +0 -2
  52. package/dist/features/categories/api/[id]/description-template/route.js +40 -1
  53. package/dist/features/categories/components/BrandDetailPageView.js +14 -3
  54. package/dist/features/categories/components/CategoryDetailPageView.js +89 -14
  55. package/dist/features/categories/components/CategoryTemplatePicker.js +9 -1
  56. package/dist/features/categories/repository/categories.repository.d.ts +65 -0
  57. package/dist/features/categories/repository/categories.repository.js +168 -22
  58. package/dist/features/categories/repository/category-counts.d.ts +143 -0
  59. package/dist/features/categories/repository/category-counts.js +224 -0
  60. package/dist/features/categories/schemas/category-counts.d.ts +155 -0
  61. package/dist/features/categories/schemas/category-counts.js +116 -0
  62. package/dist/features/categories/schemas/firestore.d.ts +0 -2
  63. package/dist/features/categories/schemas/firestore.js +0 -1
  64. package/dist/features/categories/utils/breadcrumb-chain.d.ts +194 -0
  65. package/dist/features/categories/utils/breadcrumb-chain.js +202 -0
  66. package/dist/features/corporate/schemas/index.d.ts +4 -4
  67. package/dist/features/orders/schemas/firestore.d.ts +13 -0
  68. package/dist/features/orders/types/index.d.ts +30 -0
  69. package/dist/features/parts/components/AssemblyDrawer.d.ts +107 -0
  70. package/dist/features/parts/components/AssemblyDrawer.js +250 -0
  71. package/dist/features/parts/components/ModelCompositionPanel.d.ts +37 -0
  72. package/dist/features/parts/components/ModelCompositionPanel.js +34 -0
  73. package/dist/features/parts/components/PartDetailPageView.d.ts +48 -0
  74. package/dist/features/parts/components/PartDetailPageView.js +20 -0
  75. package/dist/features/parts/components/PartsIndexPageView.d.ts +33 -0
  76. package/dist/features/parts/components/PartsIndexPageView.js +17 -0
  77. package/dist/features/parts/schemas/firestore.d.ts +257 -0
  78. package/dist/features/parts/schemas/firestore.js +181 -0
  79. package/dist/features/parts/utils/colourway-match.d.ts +62 -0
  80. package/dist/features/parts/utils/colourway-match.js +98 -0
  81. package/dist/features/parts/utils/part-breakdown.d.ts +53 -0
  82. package/dist/features/parts/utils/part-breakdown.js +77 -0
  83. package/dist/features/products/components/ProductDetailPageView.d.ts +14 -1
  84. package/dist/features/products/components/ProductDetailPageView.js +22 -3
  85. package/dist/features/products/components/ProductTabsShell.d.ts +3 -1
  86. package/dist/features/products/components/ProductTabsShell.js +4 -1
  87. package/dist/features/products/repository/category-assignment.d.ts +132 -0
  88. package/dist/features/products/repository/category-assignment.js +304 -0
  89. package/dist/features/products/repository/products.repository.d.ts +58 -1
  90. package/dist/features/products/repository/products.repository.js +255 -28
  91. package/dist/features/products/schemas/firestore.d.ts +147 -6
  92. package/dist/features/products/schemas/firestore.js +49 -0
  93. package/dist/features/search/components/SearchResultsPageView.d.ts +33 -0
  94. package/dist/features/search/components/SearchResultsPageView.js +21 -0
  95. package/dist/features/seller/components/SellerProductsView.js +129 -3
  96. package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -15
  97. package/dist/features/tester/seed-data/authored/content-discovery__parts-database.d.ts +2 -0
  98. package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +166 -0
  99. package/dist/features/tester/seed-data/authored/index.js +2 -0
  100. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +28 -1
  101. package/dist/index.d.ts +11 -16
  102. package/dist/index.js +26 -18
  103. package/dist/next/routing/route-map.d.ts +6 -2
  104. package/dist/next/routing/route-map.js +14 -1
  105. package/dist/providers/db-firebase/base.repository.d.ts +31 -0
  106. package/dist/providers/db-firebase/base.repository.js +31 -0
  107. package/dist/repositories/index.d.ts +1 -2
  108. package/dist/repositories/index.js +0 -1
  109. package/dist/seed/_helpers/category-content.d.ts +29 -0
  110. package/dist/seed/_helpers/category-content.js +98 -1
  111. package/dist/seed/_helpers/category-forest.js +104 -24
  112. package/dist/seed/_helpers/category-parts.d.ts +9 -0
  113. package/dist/seed/_helpers/category-parts.js +4594 -0
  114. package/dist/seed/carousel-slides-seed-data.js +81 -8
  115. package/dist/seed/categories-seed-data.js +44 -6
  116. package/dist/seed/homepage-sections-seed-data.js +170 -9
  117. package/dist/seed/index.d.ts +2 -0
  118. package/dist/seed/index.js +13 -0
  119. package/dist/seed/model-composition-seed-data.d.ts +15 -0
  120. package/dist/seed/model-composition-seed-data.js +8918 -0
  121. package/dist/seed/part-glossary-seed-data.d.ts +15 -0
  122. package/dist/seed/part-glossary-seed-data.js +10729 -0
  123. package/dist/seed/products-standard-seed-data.js +52 -0
  124. package/dist/seed/seed-purpose.d.ts +103 -4
  125. package/dist/seed/seed-purpose.js +162 -11
  126. package/dist/seo/json-ld.d.ts +10 -1
  127. package/dist/seo/json-ld.js +9 -1
  128. package/dist/server.d.ts +7 -0
  129. package/dist/server.js +11 -0
  130. package/dist/styles.css +1 -1
  131. package/dist/tailwind-utilities.css +1 -1
  132. package/dist/utils/id-generators.d.ts +30 -0
  133. package/dist/utils/id-generators.js +31 -1
  134. package/dist/utils/search-txt-builders.js +22 -0
  135. package/dist/utils/search-txt.d.ts +22 -0
  136. package/dist/utils/search-txt.js +17 -0
  137. package/dist/values/success-messages.d.ts +0 -4
  138. package/dist/values/success-messages.js +0 -5
  139. package/package.json +1 -1
  140. package/scripts/seed-cli.mjs +292 -16
  141. package/dist/core/copilot-log.repository.d.ts +0 -44
  142. package/dist/core/copilot-log.repository.js +0 -61
  143. package/dist/features/copilot/components/AdminCopilotView.d.ts +0 -21
  144. package/dist/features/copilot/components/AdminCopilotView.js +0 -51
  145. package/dist/features/copilot/components/index.d.ts +0 -2
  146. package/dist/features/copilot/components/index.js +0 -1
  147. package/dist/features/copilot/hooks/useCopilotChat.d.ts +0 -25
  148. package/dist/features/copilot/hooks/useCopilotChat.js +0 -65
  149. package/dist/features/copilot/hooks/useCopilotFeedback.d.ts +0 -15
  150. package/dist/features/copilot/hooks/useCopilotFeedback.js +0 -15
  151. package/dist/features/copilot/index.d.ts +0 -3
  152. package/dist/features/copilot/index.js +0 -3
@@ -1,44 +0,0 @@
1
- import type { IRepository } from "../contracts";
2
- export type CopilotFeedback = "positive" | "negative";
3
- export interface CopilotLogDocument {
4
- id: string;
5
- userId: string;
6
- userName: string;
7
- conversationId: string;
8
- prompt: string;
9
- response: string;
10
- model: string;
11
- promptTokens?: number;
12
- responseTokens?: number;
13
- durationMs?: number;
14
- feedback: CopilotFeedback | null;
15
- createdAt: Date;
16
- updatedAt?: Date;
17
- }
18
- export interface CopilotLogCreateInput {
19
- userId: string;
20
- userName: string;
21
- conversationId: string;
22
- prompt: string;
23
- response: string;
24
- model: string;
25
- promptTokens?: number;
26
- responseTokens?: number;
27
- durationMs?: number;
28
- }
29
- export declare class CopilotLogRepository {
30
- private _repo;
31
- private readonly _collection;
32
- constructor(repoOrCollection?: IRepository<CopilotLogDocument> | string | null);
33
- private get repo();
34
- create(input: CopilotLogCreateInput): Promise<CopilotLogDocument>;
35
- findByConversation(conversationId: string, limit?: number): Promise<CopilotLogDocument[]>;
36
- setFeedback(logId: string, feedback: CopilotFeedback): Promise<void>;
37
- }
38
- export declare const copilotLogRepository: CopilotLogRepository;
39
- export declare const COPILOT_LOGS_COLLECTION: "copilotLogs";
40
- export declare const COPILOT_LOGS_INDEXED_FIELDS: readonly ["userId", "conversationId", "createdAt"];
41
- export declare const copilotLogQueryHelpers: {
42
- readonly byUser: (userId: string) => readonly ["userId", "==", string];
43
- readonly byConversation: (conversationId: string) => readonly ["conversationId", "==", string];
44
- };
@@ -1,61 +0,0 @@
1
- import { getProviders } from "../contracts/index.js";
2
- function resolveRepository() {
3
- const provider = getProviders().db;
4
- if (!provider) {
5
- throw new Error("DB provider is not registered. Configure providers before using CopilotLogRepository.");
6
- }
7
- return provider.getRepository("copilotLogs");
8
- }
9
- export class CopilotLogRepository {
10
- constructor(repoOrCollection = null) {
11
- if (typeof repoOrCollection === "string") {
12
- this._repo = null;
13
- this._collection = repoOrCollection;
14
- }
15
- else {
16
- this._repo = repoOrCollection;
17
- this._collection = null;
18
- }
19
- }
20
- get repo() {
21
- if (!this._repo) {
22
- if (this._collection) {
23
- const provider = getProviders().db;
24
- if (!provider) {
25
- throw new Error("DB provider is not registered. Configure providers before using CopilotLogRepository.");
26
- }
27
- this._repo = provider.getRepository(this._collection);
28
- }
29
- else {
30
- this._repo = resolveRepository();
31
- }
32
- }
33
- return this._repo;
34
- }
35
- async create(input) {
36
- return this.repo.create({
37
- ...input,
38
- feedback: null,
39
- });
40
- }
41
- async findByConversation(conversationId, limit = 50) {
42
- const result = await this.repo.findAll({
43
- filters: `conversationId==${conversationId}`,
44
- sort: "createdAt",
45
- order: "asc",
46
- page: 1,
47
- perPage: limit,
48
- });
49
- return result.data;
50
- }
51
- async setFeedback(logId, feedback) {
52
- await this.repo.update(logId, { feedback });
53
- }
54
- }
55
- export const copilotLogRepository = new CopilotLogRepository();
56
- export const COPILOT_LOGS_COLLECTION = "copilotLogs";
57
- export const COPILOT_LOGS_INDEXED_FIELDS = ["userId", "conversationId", "createdAt"];
58
- export const copilotLogQueryHelpers = {
59
- byUser: (userId) => ["userId", "==", userId],
60
- byConversation: (conversationId) => ["conversationId", "==", conversationId],
61
- };
@@ -1,21 +0,0 @@
1
- import React from "react";
2
- export interface AdminCopilotViewProps {
3
- endpoint?: string;
4
- historyEndpoint?: string;
5
- renderHeader?: (onNewConversation: () => void) => React.ReactNode;
6
- labels?: {
7
- title?: string;
8
- newConversation?: string;
9
- noMessages?: string;
10
- noMessagesDesc?: string;
11
- inputPlaceholder?: string;
12
- sendButton?: string;
13
- sendingButton?: string;
14
- errorLabel?: string;
15
- conversationId?: string;
16
- loadConversation?: string;
17
- historyTitle?: string;
18
- };
19
- className?: string;
20
- }
21
- export declare function AdminCopilotView({ endpoint, historyEndpoint, renderHeader, labels, className, }: AdminCopilotViewProps): React.JSX.Element;
@@ -1,51 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect, useRef, useState } from "react";
4
- import { useQuery } from "@tanstack/react-query";
5
- import { Alert, Button, Div, Form, Heading, Input, Row, Span, Stack, StackedViewShell, Text } from "../../../ui/index.js";
6
- import { apiClient } from "../../../http/index.js";
7
- import { COPILOT_ENDPOINTS } from "../../../constants/api-endpoints.js";
8
- import { useCopilotChat } from "../hooks/useCopilotChat.js";
9
- const __P = {
10
- p3: "p-[var(--appkit-space-3)]",
11
- p4: "p-[var(--appkit-space-4)]",
12
- };
13
- const __O = {
14
- yAuto: "overflow-y-auto",
15
- };
16
- const LBL_CONVERSATION_ID = "Conversation ID";
17
- const CLS_ERROR_TEXT = "text-center text-[length:var(--appkit-text-sm)] text-error";
18
- function MessageBubble({ msg }) {
19
- const isUser = msg.role === "user";
20
- return (_jsx(Div, { layout: "flex", justify: isUser ? "end" : "start", children: _jsxs(Div, { textSize: "sm", className: `max-w-[80%] py-[0.625rem] ${isUser ? "bg-primary text-white" : "bg-[var(--appkit-color-surface)] dark:bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text)]"}`, padding: "x-md", style: { borderRadius: isUser ? "1.5rem 0.125rem 1.5rem 1.5rem" : "0.125rem 1.5rem 1.5rem 1.5rem" }, children: [_jsx(Text, { className: "whitespace-pre-wrap leading-relaxed", size: "sm", children: msg.content }), msg.durationMs ? (_jsxs(Span, { size: "xs", className: "mt-1 block opacity-60", children: [(msg.durationMs / 1000).toFixed(1), "s"] })) : null] }) }));
21
- }
22
- export function AdminCopilotView({ endpoint, historyEndpoint = COPILOT_ENDPOINTS.HISTORY, renderHeader, labels = {}, className = "", }) {
23
- const [input, setInput] = useState("");
24
- const [conversationInput, setConversationInput] = useState("");
25
- const messagesEndRef = useRef(null);
26
- const { messages, conversationId, sendMessage, startNewConversation, loadConversation, isLoading, error, } = useCopilotChat({ endpoint });
27
- const historyQuery = useQuery({
28
- queryKey: ["copilot-history", historyEndpoint, conversationId],
29
- queryFn: () => apiClient.get(`${historyEndpoint}?conversationId=${encodeURIComponent(conversationId)}`),
30
- staleTime: 15000,
31
- });
32
- useEffect(() => {
33
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
34
- }, [messages]);
35
- const handleSubmit = (event) => {
36
- event.preventDefault();
37
- if (!input.trim() || isLoading)
38
- return;
39
- sendMessage(input.trim());
40
- setInput("");
41
- };
42
- return (_jsx(StackedViewShell, { portal: "admin", title: labels.title ?? "AI Copilot", className: className, sections: [
43
- renderHeader ? (renderHeader(startNewConversation)) : (_jsxs(Row, { align: "center", justify: "between", gap: "3", children: [_jsx(Heading, { level: 2, children: labels.title ?? "AI Copilot" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: startNewConversation, children: labels.newConversation ?? "New Conversation" })] })),
44
- _jsxs(Div, { layout: "grid", gap: "4", className: "grid-cols-1 lg:grid-cols-[2fr,1fr]", children: [_jsxs(Stack, { className: "border border-neutral-200 h-[calc(100vh-300px)]", surface: "default", rounded: "xl", children: [_jsx(Div, { border: "bottom", className: __P.p3, children: _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", weight: "medium", children: [labels.conversationId ?? LBL_CONVERSATION_ID, ": ", conversationId] }) }), _jsxs(Stack, { className: `flex-1 ${__O.yAuto} ${__P.p4}`, gap: "md", children: [messages.length === 0 ? (_jsxs(Stack, { justify: "center", className: "h-full text-center", align: "center", children: [_jsx(Text, { weight: "medium", children: labels.noMessages ?? "No messages yet" }), _jsx(Text, { variant: "secondary", className: "mt-1", size: "sm", children: labels.noMessagesDesc ?? "Ask anything to get started" })] })) : null, messages.map((msg) => (_jsx(MessageBubble, { msg: msg }, msg.id))), isLoading ? (_jsx(Row, { justify: "start", children: _jsx(Div, { paddingY: "y-xs-tall", surface: "muted", className: "", padding: "x-md", style: { borderRadius: "0.125rem 1.5rem 1.5rem 1.5rem" }, children: _jsx(Span, { size: "sm", className: "opacity-60 animate-pulse", children: "Thinking..." }) }) })) : null, error ? (_jsx(Text, { className: CLS_ERROR_TEXT, children: labels.errorLabel ?? "An error occurred. Please try again." })) : null, _jsx(Div, { ref: messagesEndRef })] }), _jsx(Div, { border: "top", className: __P.p3, children: _jsxs(Form, { onSubmit: handleSubmit, gap: "xs", className: "flex", children: [_jsx(Input, { type: "text", bare: true, value: input, onChange: (event) => setInput(event.target.value), placeholder: labels.inputPlaceholder ?? "Ask anything...", disabled: isLoading, className: "flex-1 h-10" }), _jsx(Button, { type: "submit", variant: "primary", disabled: isLoading || !input.trim(), className: "shrink-0", children: isLoading ? labels.sendingButton ?? "Sending..." : labels.sendButton ?? "Send" })] }) })] }), _jsxs(Stack, { surface: "card", padding: "sm", gap: "3", children: [_jsx(Heading, { level: 3, size: "sm", weight: "semibold", children: labels.historyTitle ?? "Conversation History" }), _jsxs(Form, { spacing: "sm", onSubmit: (event) => {
45
- event.preventDefault();
46
- if (!conversationInput.trim())
47
- return;
48
- loadConversation(conversationInput.trim());
49
- }, children: [_jsx(Input, { label: labels.conversationId ?? LBL_CONVERSATION_ID, value: conversationInput, onChange: (event) => setConversationInput(event.target.value), placeholder: "conv_..." }), _jsx(Button, { type: "submit", variant: "secondary", size: "sm", className: "w-full", children: labels.loadConversation ?? "Load conversation" })] }), historyQuery.error ? (_jsx(Alert, { variant: "warning", title: "History unavailable", children: historyQuery.error instanceof Error ? historyQuery.error.message : "Could not load history" })) : null, _jsxs(Stack, { className: `max-h-72 ${__O.yAuto}`, gap: "sm", children: [(historyQuery.data?.messages ?? []).map((log, index) => (_jsxs(Div, { className: "border border-neutral-200", rounded: "lg", padding: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", weight: "medium", children: new Date(log.createdAt).toLocaleString() }), _jsxs(Text, { className: `mt-1`, truncate: 3, size: "sm", children: ["Q: ", log.prompt] }), _jsxs(Text, { className: `mt-1`, color: "muted", truncate: 3, size: "sm", children: ["A: ", log.response] })] }, `${log.createdAt}-${index}`))), !historyQuery.isLoading && (historyQuery.data?.messages?.length ?? 0) === 0 ? (_jsx(Text, { variant: "secondary", size: "sm", children: "No server history found for this conversation yet." })) : null] })] })] }),
50
- ] }));
51
- }
@@ -1,2 +0,0 @@
1
- export { AdminCopilotView } from "./AdminCopilotView";
2
- export type { AdminCopilotViewProps } from "./AdminCopilotView";
@@ -1 +0,0 @@
1
- export { AdminCopilotView } from "./AdminCopilotView.js";
@@ -1,25 +0,0 @@
1
- export interface CopilotMessage {
2
- id: string;
3
- role: "user" | "assistant";
4
- content: string;
5
- createdAt: string;
6
- durationMs?: number;
7
- }
8
- export interface CopilotChatResponse {
9
- response: string;
10
- durationMs?: number;
11
- }
12
- interface UseCopilotChatOptions {
13
- endpoint?: string;
14
- initialConversationId?: string;
15
- }
16
- export declare function useCopilotChat(options?: UseCopilotChatOptions): {
17
- messages: CopilotMessage[];
18
- conversationId: string;
19
- sendMessage: (prompt: string) => void;
20
- startNewConversation: () => void;
21
- loadConversation: (nextConversationId: string) => void;
22
- isLoading: boolean;
23
- error: import("@mohasinac/appkit/client").ApiError | null;
24
- };
25
- export {};
@@ -1,65 +0,0 @@
1
- "use client";
2
- import { useApiMutation } from "@mohasinac/appkit/client";
3
- import { useState, useCallback } from "react";
4
- import { apiClient } from "../../../http/index.js";
5
- import { COPILOT_ENDPOINTS } from "../../../constants/api-endpoints.js";
6
- function generateId() {
7
- return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
8
- }
9
- function generateConversationId() {
10
- return `conv_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
11
- }
12
- export function useCopilotChat(options) {
13
- const endpoint = options?.endpoint ?? COPILOT_ENDPOINTS.CHAT;
14
- const [messages, setMessages] = useState([]);
15
- const [conversationId, setConversationId] = useState(() => options?.initialConversationId ?? generateConversationId());
16
- const mutation = useApiMutation({
17
- mutationFn: async (prompt) => {
18
- const res = await apiClient.post(endpoint, { prompt, conversationId });
19
- return res.data;
20
- },
21
- onMutate: (prompt) => {
22
- const userMsg = {
23
- id: generateId(),
24
- role: "user",
25
- content: prompt,
26
- createdAt: new Date().toISOString(),
27
- };
28
- setMessages((prev) => [...prev, userMsg]);
29
- },
30
- onSuccess: (data) => {
31
- const aiMsg = {
32
- id: generateId(),
33
- role: "assistant",
34
- content: data.response,
35
- createdAt: new Date().toISOString(),
36
- durationMs: data.durationMs,
37
- };
38
- setMessages((prev) => [...prev, aiMsg]);
39
- },
40
- });
41
- const sendMessage = useCallback((prompt) => {
42
- if (!prompt.trim())
43
- return;
44
- mutation.mutate(prompt);
45
- }, [mutation]);
46
- const startNewConversation = useCallback(() => {
47
- setMessages([]);
48
- setConversationId(generateConversationId());
49
- }, []);
50
- const loadConversation = useCallback((nextConversationId) => {
51
- if (!nextConversationId.trim())
52
- return;
53
- setMessages([]);
54
- setConversationId(nextConversationId.trim());
55
- }, []);
56
- return {
57
- messages,
58
- conversationId,
59
- sendMessage,
60
- startNewConversation,
61
- loadConversation,
62
- isLoading: mutation.isPending,
63
- error: mutation.error,
64
- };
65
- }
@@ -1,15 +0,0 @@
1
- export type CopilotFeedback = "positive" | "negative";
2
- export interface UseCopilotFeedbackOptions {
3
- /** Builds the PATCH endpoint for a given log ID. */
4
- feedbackEndpoint: (logId: string) => string;
5
- }
6
- /**
7
- * useCopilotFeedback
8
- *
9
- * Sends thumbs-up / thumbs-down feedback on a copilot response.
10
- * The consumer injects the endpoint builder so appkit stays route-agnostic.
11
- */
12
- export declare function useCopilotFeedback({ feedbackEndpoint, }: UseCopilotFeedbackOptions): import("@tanstack/react-query").UseMutationResult<void, import("../../../client").ApiError, {
13
- logId: string;
14
- feedback: CopilotFeedback;
15
- }, unknown>;
@@ -1,15 +0,0 @@
1
- import { useApiMutation } from "../../../client/api/useApiMutation.js";
2
- import { apiClient } from "../../../http/index.js";
3
- /**
4
- * useCopilotFeedback
5
- *
6
- * Sends thumbs-up / thumbs-down feedback on a copilot response.
7
- * The consumer injects the endpoint builder so appkit stays route-agnostic.
8
- */
9
- export function useCopilotFeedback({ feedbackEndpoint, }) {
10
- return useApiMutation({
11
- mutationFn: async ({ logId, feedback, }) => {
12
- await apiClient.patch(feedbackEndpoint(logId), { feedback });
13
- },
14
- });
15
- }
@@ -1,3 +0,0 @@
1
- export * from "./components";
2
- export * from "./hooks/useCopilotChat";
3
- export * from "./hooks/useCopilotFeedback";
@@ -1,3 +0,0 @@
1
- export * from "./components/index.js";
2
- export * from "./hooks/useCopilotChat.js";
3
- export * from "./hooks/useCopilotFeedback.js";