@mohasinac/appkit 4.40.1 → 4.41.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.
- package/dist/features/categories/repository/categories.repository.js +2 -2
- package/dist/features/shell/SectionForm.js +44 -5
- package/dist/features/tester/seed-data/_money-flows.js +65 -49
- package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +6 -4
- package/dist/features/tester/seed-data/authored/admin__coupons.js +14 -13
- package/dist/features/tester/seed-data/authored/buying__bidding.js +154 -140
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +59 -56
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +18 -18
- package/dist/features/tester/seed-data/authored/buying__cart.js +105 -79
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +6 -8
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +13 -13
- package/dist/features/tester/seed-data/authored/buying__offers.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +8 -7
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +62 -56
- package/dist/features/tester/seed-data/authored/buying__return-request.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__reviews.js +1 -1
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +8 -8
- package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +1 -1
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +29 -16
- package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +9 -9
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +69 -36
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +1 -1
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +3 -3
- package/dist/features/tester/seed-data/authored/index.js +0 -2
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +2 -2
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +6 -4
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +2 -2
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +1 -1
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +8 -10
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +2 -2
- package/dist/features/tester/seed-data/authored/seo__og-images.js +3 -4
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +6 -8
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +5 -5
- package/dist/features/tester/seed-data/index.d.ts +0 -10
- package/dist/features/tester/seed-data/index.js +0 -10
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +75 -89
- package/dist/features/tester/seed-data/tester-responses-seed-data.js +5 -5
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -21
- package/dist/seed/addresses-seed-data.js +0 -34
- package/dist/seed/index.d.ts +1 -1
- package/dist/seed/index.js +4 -3
- package/dist/seed/manifest.js +11 -12
- package/dist/seed/notifications-seed-data.js +4 -4
- package/dist/seed/stores-seed-data.js +7 -52
- package/dist/seed/users-seed-data.js +3 -83
- package/package.json +2 -2
- package/scripts/seed-cli.mjs +15 -20
- package/dist/_internal/server/features/classified/actions.d.ts +0 -12
- package/dist/_internal/server/features/classified/actions.js +0 -33
- package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
- package/dist/_internal/server/features/digital-code/actions.js +0 -33
- package/dist/_internal/server/features/homepage/data.d.ts +0 -18
- package/dist/_internal/server/features/homepage/data.js +0 -70
- package/dist/_internal/server/features/live/actions.d.ts +0 -6
- package/dist/_internal/server/features/live/actions.js +0 -27
- package/dist/_internal/server/features/messages/actions.d.ts +0 -6
- package/dist/_internal/server/features/messages/actions.js +0 -6
- package/dist/_internal/server/features/messages/data.d.ts +0 -10
- package/dist/_internal/server/features/messages/data.js +0 -24
- package/dist/_internal/server/features/messages/index.d.ts +0 -2
- package/dist/_internal/server/features/messages/index.js +0 -2
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
- package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
- package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
- package/dist/_internal/shared/features/lottery/config-form.js +0 -71
- package/dist/client/api/useFeatureFlags.d.ts +0 -22
- package/dist/client/api/useFeatureFlags.js +0 -27
- package/dist/features/account/address-validation.d.ts +0 -20
- package/dist/features/account/address-validation.js +0 -35
- package/dist/features/account/components/ChatList.d.ts +0 -14
- package/dist/features/account/components/ChatList.js +0 -9
- package/dist/features/account/components/ChatWindow.d.ts +0 -17
- package/dist/features/account/components/ChatWindow.js +0 -6
- package/dist/features/account/components/MessagesView.d.ts +0 -16
- package/dist/features/account/components/MessagesView.js +0 -5
- package/dist/features/account/components/UserOffersView.d.ts +0 -10
- package/dist/features/account/components/UserOffersView.js +0 -5
- package/dist/features/account/constants/addresses.d.ts +0 -13
- package/dist/features/account/constants/addresses.js +0 -43
- package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
- package/dist/features/account/hooks/useAddressForm.js +0 -58
- package/dist/features/admin/actions/chat-actions.d.ts +0 -29
- package/dist/features/admin/actions/chat-actions.js +0 -101
- package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
- package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
- package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
- package/dist/features/admin/components/AdminSiteView.js +0 -52
- package/dist/features/admin/hooks/useChat.d.ts +0 -24
- package/dist/features/admin/hooks/useChat.js +0 -100
- package/dist/features/admin/permission-map.d.ts +0 -3
- package/dist/features/admin/permission-map.js +0 -26
- package/dist/features/admin/repository/chat.repository.d.ts +0 -50
- package/dist/features/admin/repository/chat.repository.js +0 -223
- package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
- package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
- package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
- package/dist/features/auth/actions/realtime-token-actions.js +0 -38
- package/dist/features/auth/password-change-otp.d.ts +0 -34
- package/dist/features/auth/password-change-otp.js +0 -56
- package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
- package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
- package/dist/features/events/api/route.d.ts +0 -12
- package/dist/features/events/api/route.js +0 -90
- package/dist/features/faq/api/route.d.ts +0 -11
- package/dist/features/faq/api/route.js +0 -52
- package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
- package/dist/features/faq/hooks/useFAQs.js +0 -41
- package/dist/features/media/upload/video-poster.test.d.ts +0 -1
- package/dist/features/media/upload/video-poster.test.js +0 -42
- package/dist/features/messages/actions/index.d.ts +0 -2
- package/dist/features/messages/actions/index.js +0 -2
- package/dist/features/messages/actions/messages-actions.d.ts +0 -15
- package/dist/features/messages/actions/messages-actions.js +0 -33
- package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
- package/dist/features/messages/actions/ping-rtdb.js +0 -26
- package/dist/features/messages/hooks/useConversation.d.ts +0 -22
- package/dist/features/messages/hooks/useConversation.js +0 -155
- package/dist/features/messages/hooks/useConversations.d.ts +0 -15
- package/dist/features/messages/hooks/useConversations.js +0 -104
- package/dist/features/messages/index.d.ts +0 -6
- package/dist/features/messages/index.js +0 -4
- package/dist/features/messages/realtime.d.ts +0 -32
- package/dist/features/messages/realtime.js +0 -39
- package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
- package/dist/features/messages/repository/conversations.repository.js +0 -284
- package/dist/features/messages/schemas/firestore.d.ts +0 -34
- package/dist/features/messages/schemas/firestore.js +0 -16
- package/dist/features/messages/schemas/index.d.ts +0 -177
- package/dist/features/messages/schemas/index.js +0 -35
- package/dist/features/messages/server.d.ts +0 -6
- package/dist/features/messages/server.js +0 -6
- package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
- package/dist/features/products/components/MakeOfferForm.js +0 -9
- package/dist/features/reviews/api/route.d.ts +0 -21
- package/dist/features/reviews/api/route.js +0 -174
- package/dist/features/seller/api/offers/route.d.ts +0 -17
- package/dist/features/seller/api/offers/route.js +0 -63
- package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
- package/dist/features/seller/components/SellerAuctionsView.js +0 -113
- package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
- package/dist/features/seller/components/SellerOffersPanel.js +0 -160
- package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
- package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
- package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
- package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
- package/dist/features/seller/permission-map.d.ts +0 -5
- package/dist/features/seller/permission-map.js +0 -17
- package/dist/features/shell/StepForm.d.ts +0 -80
- package/dist/features/shell/StepForm.js +0 -136
- package/dist/features/stores/api/route.d.ts +0 -12
- package/dist/features/stores/api/route.js +0 -110
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
- package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
- package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
- package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
- package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
- package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
- package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
- package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
- package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
- package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
- package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
- package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
- package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
- package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
- package/dist/monitoring/analytics.d.ts +0 -80
- package/dist/monitoring/analytics.js +0 -176
- package/dist/next/middleware/pii-redactor.d.ts +0 -32
- package/dist/next/middleware/pii-redactor.js +0 -84
- package/dist/providers/db-firebase/realtime.d.ts +0 -42
- package/dist/providers/db-firebase/realtime.js +0 -138
- package/dist/security/rbac/Can.d.ts +0 -31
- package/dist/security/rbac/Can.js +0 -22
- package/dist/security/rbac/default-roles.d.ts +0 -2
- package/dist/security/rbac/default-roles.js +0 -83
- package/dist/security/rbac/hook.d.ts +0 -20
- package/dist/security/rbac/hook.js +0 -30
- package/dist/security/rbac/index.d.ts +0 -8
- package/dist/security/rbac/index.js +0 -6
- package/dist/security/rbac/middleware.d.ts +0 -51
- package/dist/security/rbac/middleware.js +0 -51
- package/dist/security/rbac/resolver.d.ts +0 -5
- package/dist/security/rbac/resolver.js +0 -38
- package/dist/security/rbac/server.d.ts +0 -24
- package/dist/security/rbac/server.js +0 -42
- package/dist/security/rbac/types.d.ts +0 -22
- package/dist/security/rbac/types.js +0 -2
- package/dist/seed/conversations-seed-data.d.ts +0 -2
- package/dist/seed/conversations-seed-data.js +0 -292
- package/dist/utils/filter.helper.d.ts +0 -18
- package/dist/utils/filter.helper.js +0 -21
- package/dist/utils/pagination.helper.d.ts +0 -23
- package/dist/utils/pagination.helper.js +0 -24
- package/dist/utils/search-tokens.d.ts +0 -2
- package/dist/utils/search-tokens.js +0 -21
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Div, Heading, Row, Span } from "../../../ui";
|
|
3
|
-
const CLS_DOT_ON = "bg-success-surface";
|
|
4
|
-
export function ChatWindow({ labels = {}, isConnected = true, isLoading = false, error, renderLoadingIndicator, renderMessages, renderInput, className = "", }) {
|
|
5
|
-
return (_jsxs(Div, { className: className, children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] mb-3", padding: "b-sm", children: [_jsxs(Row, { gap: "xs", children: [labels.title && _jsx(Heading, { level: 4, children: labels.title }), _jsx(Span, { className: `w-2 h-2 ${isConnected ? CLS_DOT_ON : "bg-[var(--appkit-color-text-faint)]"}`, rounded: "full", "aria-label": isConnected ? labels.connected : labels.disconnected })] }), isLoading && (renderLoadingIndicator?.() ?? null)] }), error ?? null, renderMessages(), renderInput()] }));
|
|
6
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
export interface MessagesViewLabels {
|
|
3
|
-
title?: string;
|
|
4
|
-
selectRoom?: string;
|
|
5
|
-
backToList?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface MessagesViewProps {
|
|
8
|
-
labels?: MessagesViewLabels;
|
|
9
|
-
chatId?: string | null;
|
|
10
|
-
renderChatList?: () => React.ReactNode;
|
|
11
|
-
renderChatWindow?: () => React.ReactNode;
|
|
12
|
-
renderMobileBack?: () => React.ReactNode;
|
|
13
|
-
renderEmptyState?: () => React.ReactNode;
|
|
14
|
-
className?: string;
|
|
15
|
-
}
|
|
16
|
-
export declare function MessagesView({ labels, chatId, renderChatList, renderChatWindow, renderMobileBack, renderEmptyState, className, }: MessagesViewProps): React.JSX.Element;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Div, Heading, Span, Stack } from "../../../ui";
|
|
3
|
-
export function MessagesView({ labels = {}, chatId, renderChatList, renderChatWindow, renderMobileBack, renderEmptyState, className = "", }) {
|
|
4
|
-
return (_jsxs(Div, { layout: "grid", gap: "4", className: `grid-cols-1 md:grid-cols-[280px_1fr] xl:grid-cols-[320px_1fr] 2xl:grid-cols-[360px_1fr] h-full min-h-[600px] ${className}`, children: [_jsxs(Div, { className: chatId ? "hidden md:block" : "block", children: [labels.title && (_jsx(Heading, { level: 3, className: "mb-3", weight: "semibold", children: labels.title })), renderChatList?.()] }), chatId ? (_jsxs(Stack, { gap: "xs", children: [renderMobileBack?.(), renderChatWindow?.()] })) : (_jsx(Div, { className: "hidden md:flex text-[var(--appkit-color-text-faint)] border border-dashed border-[var(--appkit-color-border)]", align: "center", justify: "center", rounded: "xl", children: renderEmptyState?.() ?? (_jsx(Span, { children: labels.selectRoom ?? "Select a conversation" })) }))] }));
|
|
5
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { StackedViewShellProps } from "../../../ui";
|
|
3
|
-
export interface UserOffersViewLabels {
|
|
4
|
-
title?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface UserOffersViewProps extends Omit<StackedViewShellProps, "sections"> {
|
|
7
|
-
labels?: UserOffersViewLabels;
|
|
8
|
-
renderTable?: () => React.ReactNode;
|
|
9
|
-
}
|
|
10
|
-
export declare function UserOffersView({ labels, renderTable, ...rest }: UserOffersViewProps): React.JSX.Element;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { StackedViewShell } from "../../../ui";
|
|
3
|
-
export function UserOffersView({ labels = {}, renderTable, ...rest }) {
|
|
4
|
-
return (_jsx(StackedViewShell, { portal: "user", ...rest, title: labels.title, sections: [renderTable?.()] }));
|
|
5
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare const ADDRESS_TYPES: readonly [{
|
|
2
|
-
readonly value: "home";
|
|
3
|
-
readonly label: "Home";
|
|
4
|
-
}, {
|
|
5
|
-
readonly value: "work";
|
|
6
|
-
readonly label: "Work";
|
|
7
|
-
}, {
|
|
8
|
-
readonly value: "other";
|
|
9
|
-
readonly label: "Other";
|
|
10
|
-
}];
|
|
11
|
-
export type AddressType = (typeof ADDRESS_TYPES)[number]["value"];
|
|
12
|
-
export declare const INDIAN_STATES: readonly ["Andhra Pradesh", "Arunachal Pradesh", "Assam", "Bihar", "Chhattisgarh", "Goa", "Gujarat", "Haryana", "Himachal Pradesh", "Jharkhand", "Karnataka", "Kerala", "Madhya Pradesh", "Maharashtra", "Manipur", "Meghalaya", "Mizoram", "Nagaland", "Odisha", "Punjab", "Rajasthan", "Sikkim", "Tamil Nadu", "Telangana", "Tripura", "Uttar Pradesh", "Uttarakhand", "West Bengal", "Andaman and Nicobar Islands", "Chandigarh", "Dadra and Nagar Haveli and Daman and Diu", "Delhi", "Jammu and Kashmir", "Ladakh", "Lakshadweep", "Puducherry"];
|
|
13
|
-
export type IndianState = (typeof INDIAN_STATES)[number];
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export const ADDRESS_TYPES = [
|
|
2
|
-
{ value: "home", label: "Home" },
|
|
3
|
-
{ value: "work", label: "Work" },
|
|
4
|
-
{ value: "other", label: "Other" },
|
|
5
|
-
];
|
|
6
|
-
export const INDIAN_STATES = [
|
|
7
|
-
"Andhra Pradesh",
|
|
8
|
-
"Arunachal Pradesh",
|
|
9
|
-
"Assam",
|
|
10
|
-
"Bihar",
|
|
11
|
-
"Chhattisgarh",
|
|
12
|
-
"Goa",
|
|
13
|
-
"Gujarat",
|
|
14
|
-
"Haryana",
|
|
15
|
-
"Himachal Pradesh",
|
|
16
|
-
"Jharkhand",
|
|
17
|
-
"Karnataka",
|
|
18
|
-
"Kerala",
|
|
19
|
-
"Madhya Pradesh",
|
|
20
|
-
"Maharashtra",
|
|
21
|
-
"Manipur",
|
|
22
|
-
"Meghalaya",
|
|
23
|
-
"Mizoram",
|
|
24
|
-
"Nagaland",
|
|
25
|
-
"Odisha",
|
|
26
|
-
"Punjab",
|
|
27
|
-
"Rajasthan",
|
|
28
|
-
"Sikkim",
|
|
29
|
-
"Tamil Nadu",
|
|
30
|
-
"Telangana",
|
|
31
|
-
"Tripura",
|
|
32
|
-
"Uttar Pradesh",
|
|
33
|
-
"Uttarakhand",
|
|
34
|
-
"West Bengal",
|
|
35
|
-
"Andaman and Nicobar Islands",
|
|
36
|
-
"Chandigarh",
|
|
37
|
-
"Dadra and Nagar Haveli and Daman and Diu",
|
|
38
|
-
"Delhi",
|
|
39
|
-
"Jammu and Kashmir",
|
|
40
|
-
"Ladakh",
|
|
41
|
-
"Lakshadweep",
|
|
42
|
-
"Puducherry",
|
|
43
|
-
];
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface AddressFormStateData {
|
|
2
|
-
fullName: string;
|
|
3
|
-
phoneNumber: string;
|
|
4
|
-
pincode: string;
|
|
5
|
-
addressLine1: string;
|
|
6
|
-
addressLine2: string;
|
|
7
|
-
landmark: string;
|
|
8
|
-
city: string;
|
|
9
|
-
state: string;
|
|
10
|
-
addressType: string;
|
|
11
|
-
isDefault: boolean;
|
|
12
|
-
}
|
|
13
|
-
interface UseAddressFormResult {
|
|
14
|
-
formData: AddressFormStateData;
|
|
15
|
-
errors: Record<string, string>;
|
|
16
|
-
handleChange: (field: keyof AddressFormStateData, value: string | boolean) => void;
|
|
17
|
-
validate: () => boolean;
|
|
18
|
-
reset: (data?: Partial<AddressFormStateData>) => void;
|
|
19
|
-
setFormData: React.Dispatch<React.SetStateAction<AddressFormStateData>>;
|
|
20
|
-
}
|
|
21
|
-
export declare function useAddressForm(initialData?: Partial<AddressFormStateData>, options?: {
|
|
22
|
-
validateFn?: (data: AddressFormStateData) => Record<string, string>;
|
|
23
|
-
}): UseAddressFormResult;
|
|
24
|
-
export {};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useCallback, useState } from "react";
|
|
3
|
-
const DEFAULT_FORM_DATA = {
|
|
4
|
-
fullName: "",
|
|
5
|
-
phoneNumber: "",
|
|
6
|
-
pincode: "",
|
|
7
|
-
addressLine1: "",
|
|
8
|
-
addressLine2: "",
|
|
9
|
-
landmark: "",
|
|
10
|
-
city: "",
|
|
11
|
-
state: "",
|
|
12
|
-
addressType: "home",
|
|
13
|
-
isDefault: false,
|
|
14
|
-
};
|
|
15
|
-
function defaultValidate(data) {
|
|
16
|
-
const errors = {};
|
|
17
|
-
if (!data.fullName.trim())
|
|
18
|
-
errors.fullName = "Full name is required";
|
|
19
|
-
if (!data.phoneNumber.trim())
|
|
20
|
-
errors.phoneNumber = "Phone number is required";
|
|
21
|
-
if (!data.addressLine1.trim())
|
|
22
|
-
errors.addressLine1 = "Address line 1 is required";
|
|
23
|
-
if (!data.city.trim())
|
|
24
|
-
errors.city = "City is required";
|
|
25
|
-
if (!data.state.trim())
|
|
26
|
-
errors.state = "State is required";
|
|
27
|
-
if (!data.pincode.trim())
|
|
28
|
-
errors.pincode = "Pincode is required";
|
|
29
|
-
return errors;
|
|
30
|
-
}
|
|
31
|
-
export function useAddressForm(initialData = {}, options) {
|
|
32
|
-
const [formData, setFormData] = useState({
|
|
33
|
-
...DEFAULT_FORM_DATA,
|
|
34
|
-
...initialData,
|
|
35
|
-
});
|
|
36
|
-
const [errors, setErrors] = useState({});
|
|
37
|
-
const validateFn = options?.validateFn ?? defaultValidate;
|
|
38
|
-
const handleChange = useCallback((field, value) => {
|
|
39
|
-
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
40
|
-
if (errors[field]) {
|
|
41
|
-
setErrors((prev) => {
|
|
42
|
-
const next = { ...prev };
|
|
43
|
-
delete next[field];
|
|
44
|
-
return next;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}, [errors]);
|
|
48
|
-
const validate = useCallback(() => {
|
|
49
|
-
const newErrors = validateFn(formData);
|
|
50
|
-
setErrors(newErrors);
|
|
51
|
-
return Object.keys(newErrors).length === 0;
|
|
52
|
-
}, [formData, validateFn]);
|
|
53
|
-
const reset = useCallback((data = {}) => {
|
|
54
|
-
setFormData({ ...DEFAULT_FORM_DATA, ...data });
|
|
55
|
-
setErrors({});
|
|
56
|
-
}, []);
|
|
57
|
-
return { formData, errors, handleChange, validate, reset, setFormData };
|
|
58
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat Domain Actions — appkit
|
|
3
|
-
*
|
|
4
|
-
* Pure async functions for buyer↔seller chat. No auth, no rate-limit.
|
|
5
|
-
* Accept userId as explicit parameter. Called by letitrip thin wrappers.
|
|
6
|
-
*
|
|
7
|
-
* chatEnabled must be passed from the consumer (e.g. FEATURE_FLAGS.CHAT_ENABLED)
|
|
8
|
-
* rather than reading it from appkit to keep market config in letitrip.
|
|
9
|
-
*/
|
|
10
|
-
import type { ChatRoomDocument } from "../repository/chat.repository";
|
|
11
|
-
export interface ChatRoomsResult {
|
|
12
|
-
rooms: ChatRoomDocument[];
|
|
13
|
-
}
|
|
14
|
-
export interface CreateRoomInput {
|
|
15
|
-
orderId: string;
|
|
16
|
-
ownerId: string;
|
|
17
|
-
}
|
|
18
|
-
export interface CreateRoomResult {
|
|
19
|
-
room: ChatRoomDocument;
|
|
20
|
-
}
|
|
21
|
-
export declare function getChatRooms(userId: string, chatEnabled: boolean): Promise<ChatRoomsResult>;
|
|
22
|
-
export declare function createOrGetChatRoom(userId: string, chatEnabled: boolean, input: CreateRoomInput): Promise<CreateRoomResult>;
|
|
23
|
-
export declare function sendChatMessage(userId: string, chatId: string, message: string): Promise<{
|
|
24
|
-
messageId: string;
|
|
25
|
-
timestamp: number;
|
|
26
|
-
}>;
|
|
27
|
-
export declare function deleteChatRoom(userId: string, chatId: string): Promise<{
|
|
28
|
-
deleted: boolean;
|
|
29
|
-
}>;
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat Domain Actions — appkit
|
|
3
|
-
*
|
|
4
|
-
* Pure async functions for buyer↔seller chat. No auth, no rate-limit.
|
|
5
|
-
* Accept userId as explicit parameter. Called by letitrip thin wrappers.
|
|
6
|
-
*
|
|
7
|
-
* chatEnabled must be passed from the consumer (e.g. FEATURE_FLAGS.CHAT_ENABLED)
|
|
8
|
-
* rather than reading it from appkit to keep market config in letitrip.
|
|
9
|
-
*/
|
|
10
|
-
import { chatRepository } from "../repository/chat.repository";
|
|
11
|
-
import { orderRepository } from "../../orders/repository/orders.repository";
|
|
12
|
-
import { userRepository } from "../../auth/repository/user.repository";
|
|
13
|
-
import { getAdminRealtimeDb } from "../../../providers/db-firebase/index";
|
|
14
|
-
import { AuthorizationError, NotFoundError, ValidationError, } from "../../../errors/index";
|
|
15
|
-
import { ERROR_MESSAGES } from "../../../errors/messages";
|
|
16
|
-
import { serverLogger } from "../../../monitoring/index";
|
|
17
|
-
import { normalizeError } from "../../../errors/normalize";
|
|
18
|
-
export async function getChatRooms(userId, chatEnabled) {
|
|
19
|
-
if (!chatEnabled)
|
|
20
|
-
throw new AuthorizationError("Chat is temporarily unavailable.");
|
|
21
|
-
const rooms = await chatRepository.listForUser(userId);
|
|
22
|
-
return { rooms };
|
|
23
|
-
}
|
|
24
|
-
export async function createOrGetChatRoom(userId, chatEnabled, input) {
|
|
25
|
-
if (!chatEnabled)
|
|
26
|
-
throw new AuthorizationError("Chat is temporarily unavailable.");
|
|
27
|
-
const { orderId, ownerId } = input;
|
|
28
|
-
const order = await orderRepository.findById(orderId);
|
|
29
|
-
if (!order)
|
|
30
|
-
throw new NotFoundError(ERROR_MESSAGES.ORDER.NOT_FOUND);
|
|
31
|
-
if (order.userId !== userId && ownerId !== userId)
|
|
32
|
-
throw new AuthorizationError(ERROR_MESSAGES.CHAT.NOT_AUTHORIZED);
|
|
33
|
-
const buyerId = order.userId;
|
|
34
|
-
const existing = await chatRepository.findRoom(buyerId, ownerId, orderId);
|
|
35
|
-
if (existing) {
|
|
36
|
-
const deletedBy = existing.deletedBy ?? [];
|
|
37
|
-
if (deletedBy.includes(userId)) {
|
|
38
|
-
const reopened = deletedBy.filter((id) => id !== userId);
|
|
39
|
-
await chatRepository.update(existing.id, { deletedBy: reopened });
|
|
40
|
-
return { room: { ...existing, deletedBy: reopened } };
|
|
41
|
-
}
|
|
42
|
-
return { room: existing };
|
|
43
|
-
}
|
|
44
|
-
const [buyer, owner] = await Promise.all([
|
|
45
|
-
userRepository.findById(buyerId),
|
|
46
|
-
userRepository.findById(ownerId),
|
|
47
|
-
]);
|
|
48
|
-
const room = await chatRepository.create({
|
|
49
|
-
buyerId,
|
|
50
|
-
ownerId,
|
|
51
|
-
orderId,
|
|
52
|
-
productId: order.productId,
|
|
53
|
-
productTitle: order.productTitle,
|
|
54
|
-
buyerName: buyer?.displayName ?? "Buyer",
|
|
55
|
-
ownerName: owner?.displayName ?? "Seller",
|
|
56
|
-
participantIds: [buyerId, ownerId],
|
|
57
|
-
});
|
|
58
|
-
serverLogger.info("createOrGetChatRoom: room created", { userId, orderId });
|
|
59
|
-
return { room };
|
|
60
|
-
}
|
|
61
|
-
export async function sendChatMessage(userId, chatId, message) {
|
|
62
|
-
if (!chatId?.trim())
|
|
63
|
-
throw new ValidationError("chatId is required");
|
|
64
|
-
if (!message?.trim())
|
|
65
|
-
throw new ValidationError("message is required");
|
|
66
|
-
const room = await chatRepository.findById(chatId);
|
|
67
|
-
if (!room)
|
|
68
|
-
throw new NotFoundError("Chat room not found");
|
|
69
|
-
if (!(room.participantIds ?? []).includes(userId))
|
|
70
|
-
throw new AuthorizationError("Not a participant of this chat");
|
|
71
|
-
const rtdb = getAdminRealtimeDb();
|
|
72
|
-
const msgRef = rtdb.ref(`/chat/${chatId}/messages`).push();
|
|
73
|
-
const id = msgRef.key;
|
|
74
|
-
const userName = userId === room.buyerId
|
|
75
|
-
? (room.buyerName ?? "Buyer")
|
|
76
|
-
: userId === room.ownerId
|
|
77
|
-
? (room.ownerName ?? "Seller")
|
|
78
|
-
: (room.buyerName ?? "Member");
|
|
79
|
-
await msgRef.set({ userId, userName, message, timestamp: Date.now() });
|
|
80
|
-
chatRepository.updateLastMessage(chatId, message).catch((err) => {
|
|
81
|
-
serverLogger.warn("Failed to update chat lastMessage", {
|
|
82
|
-
chatId,
|
|
83
|
-
error: normalizeError(err).message,
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
serverLogger.debug("sendChatMessage", { userId, chatId });
|
|
87
|
-
return { messageId: id, timestamp: Date.now() };
|
|
88
|
-
}
|
|
89
|
-
export async function deleteChatRoom(userId, chatId) {
|
|
90
|
-
if (!chatId?.trim())
|
|
91
|
-
throw new ValidationError("chatId is required");
|
|
92
|
-
const room = await chatRepository.findById(chatId);
|
|
93
|
-
if (!room)
|
|
94
|
-
throw new NotFoundError("Chat room not found");
|
|
95
|
-
const deletedBy = room.deletedBy ?? [];
|
|
96
|
-
if (!deletedBy.includes(userId)) {
|
|
97
|
-
await chatRepository.update(chatId, { deletedBy: [...deletedBy, userId] });
|
|
98
|
-
}
|
|
99
|
-
serverLogger.info("deleteChatRoom: soft-deleted", { userId, chatId });
|
|
100
|
-
return { deleted: true };
|
|
101
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { StackedViewShellProps } from "../../../ui";
|
|
3
|
-
export interface AdminFeatureFlagsViewProps extends Omit<StackedViewShellProps, "sections"> {
|
|
4
|
-
labels?: {
|
|
5
|
-
title?: string;
|
|
6
|
-
};
|
|
7
|
-
renderFlags?: () => React.ReactNode;
|
|
8
|
-
}
|
|
9
|
-
export declare function AdminFeatureFlagsView({ labels, renderFlags, ...rest }: AdminFeatureFlagsViewProps): React.JSX.Element;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Button, Div, Form, FormActions, Input, Row, Stack, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
|
|
7
|
-
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
-
import { apiClient } from "../../../http";
|
|
9
|
-
import { featureFlagsUpdateSchema } from "../schemas/admin-ops-forms";
|
|
10
|
-
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
|
|
11
|
-
const __O = {
|
|
12
|
-
hidden: "overflow-hidden",
|
|
13
|
-
};
|
|
14
|
-
// Platform feature keys (flat booleans with rollout % support)
|
|
15
|
-
const PLATFORM_FLAGS = [
|
|
16
|
-
{ key: "blog", label: "Blog Posts", desc: "Publish articles for admins / sellers" },
|
|
17
|
-
{ key: "events", label: "Events", desc: "Raffles, spin wheels, polls" },
|
|
18
|
-
{ key: "reviews", label: "Reviews", desc: "Product review system" },
|
|
19
|
-
{ key: "wishlists", label: "Wishlists", desc: "Per-user saved lists" },
|
|
20
|
-
{ key: "coupons", label: "Coupons", desc: "Discount code system" },
|
|
21
|
-
{ key: "offers", label: "Buyer Offers", desc: "Make-an-offer price negotiation" },
|
|
22
|
-
{ key: "notifications", label: "Notifications", desc: "In-app notification feed" },
|
|
23
|
-
{ key: "chats", label: "Live Chat", desc: "Buyer-seller messaging" },
|
|
24
|
-
{ key: "sellerRegistration", label: "Seller Reg.", desc: "New vendor registration" },
|
|
25
|
-
{ key: "smsVerification", label: "SMS Verify", desc: "SMS OTP verification" },
|
|
26
|
-
{ key: "translations", label: "Translations", desc: "Multi-language support" },
|
|
27
|
-
{ key: "seedPanel", label: "Seed Panel", desc: "Dev seed data panel" },
|
|
28
|
-
];
|
|
29
|
-
// Listing type keys (nested under featureFlags.listingTypes — no rollout %)
|
|
30
|
-
const LISTING_TYPE_FLAGS = [
|
|
31
|
-
{ key: "standard", label: "Standard", desc: "Fixed-price products (Phase 1)" },
|
|
32
|
-
{ key: "auction", label: "Auction", desc: "eBay-style bidding (Phase 1)" },
|
|
33
|
-
{ key: "pre-order", label: "Pre-order", desc: "Future delivery + deposit (Phase 1)" },
|
|
34
|
-
{ key: "prize-draw", label: "Prize Draw", desc: "Raffle reveal window (Phase 1)" },
|
|
35
|
-
{ key: "classified", label: "Classified", desc: "Chat-only / no cart (Phase 2)" },
|
|
36
|
-
{ key: "digital-code", label: "Digital Code", desc: "Steam-key instant delivery (Phase 2)" },
|
|
37
|
-
{ key: "live", label: "Live Items", desc: "Animals / plants + verification (Phase 2)" },
|
|
38
|
-
];
|
|
39
|
-
// Category type keys (nested under featureFlags.categoryTypes — no rollout %)
|
|
40
|
-
const CATEGORY_TYPE_FLAGS = [
|
|
41
|
-
{ key: "category", label: "Categories", desc: "Standard hierarchy tier 1–3" },
|
|
42
|
-
{ key: "sublisting", label: "Sublistings", desc: "Grading / card-number sub-tiers" },
|
|
43
|
-
{ key: "brand", label: "Brands", desc: "Brand storefront pages" },
|
|
44
|
-
{ key: "bundle", label: "Bundles", desc: "Curated product collections" },
|
|
45
|
-
];
|
|
46
|
-
function AccordionSection({ title, defaultOpen = true, children }) {
|
|
47
|
-
const [open, setOpen] = React.useState(defaultOpen);
|
|
48
|
-
return (_jsxs(Div, { className: `${__O.hidden}`, rounded: "lg", border: "default", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => setOpen((v) => !v), paddingX: "md", paddingY: "md", className: "w-full text-left bg-[var(--appkit-color-surface-elevated)]/60", "aria-expanded": open, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: title }), _jsx("svg", { className: `h-4 w-4 text-zinc-400 transition-transform ${open ? "rotate-180" : ""} shrink-0`, fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }) }), open && (_jsx(Div, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", children: children }))] }));
|
|
49
|
-
}
|
|
50
|
-
function FlagRow({ label, desc, checked, onChange, rollout, onRolloutChange, showRollout }) {
|
|
51
|
-
return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", justify: "between", gap: "md", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Toggle, { checked: checked, onChange: onChange, label: label }), _jsx(Text, { className: "mt-0.5 ml-10 truncate", color: "faint", size: "xs", children: desc })] }), showRollout && (_jsxs(Stack, { className: "w-28 shrink-0", gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Rollout %" }), _jsx(Input, { type: "number", min: 0, max: 100, value: rollout ?? 100, onChange: (e) => onRolloutChange?.(Math.min(100, Math.max(0, Number(e.target.value)))), disabled: !checked, className: "w-full" })] }))] }));
|
|
52
|
-
}
|
|
53
|
-
export function AdminFeatureFlagsView({ labels = {}, renderFlags, ...rest }) {
|
|
54
|
-
const queryClient = useQueryClient();
|
|
55
|
-
const { showToast } = useToast();
|
|
56
|
-
const { data, isLoading, error } = useQuery({
|
|
57
|
-
queryKey: ["admin", "feature-flags"],
|
|
58
|
-
queryFn: async () => {
|
|
59
|
-
const res = await apiClient.get(ADMIN_ENDPOINTS.FEATURE_FLAGS);
|
|
60
|
-
return res.data ?? { flags: {}, rollouts: {} };
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
const [flags, setFlags] = React.useState({});
|
|
64
|
-
const [rollouts, setRollouts] = React.useState({});
|
|
65
|
-
React.useEffect(() => {
|
|
66
|
-
if (!data)
|
|
67
|
-
return;
|
|
68
|
-
setFlags(data.flags ?? {});
|
|
69
|
-
setRollouts(data.rollouts ?? {});
|
|
70
|
-
}, [data]);
|
|
71
|
-
const getPlatformFlag = (key) => Boolean(flags[key]);
|
|
72
|
-
const setPlatformFlag = (key, val) => setFlags((prev) => ({ ...prev, [key]: val }));
|
|
73
|
-
const getListingTypeFlag = (key) => {
|
|
74
|
-
const lt = flags.listingTypes;
|
|
75
|
-
return lt?.[key] ?? false;
|
|
76
|
-
};
|
|
77
|
-
const setListingTypeFlag = (key, val) => setFlags((prev) => ({
|
|
78
|
-
...prev,
|
|
79
|
-
listingTypes: { ...(prev.listingTypes ?? {}), [key]: val },
|
|
80
|
-
}));
|
|
81
|
-
const getCategoryTypeFlag = (key) => {
|
|
82
|
-
const ct = flags.categoryTypes;
|
|
83
|
-
return ct?.[key] ?? false;
|
|
84
|
-
};
|
|
85
|
-
const setCategoryTypeFlag = (key, val) => setFlags((prev) => ({
|
|
86
|
-
...prev,
|
|
87
|
-
categoryTypes: { ...(prev.categoryTypes ?? {}), [key]: val },
|
|
88
|
-
}));
|
|
89
|
-
const saveFlags = useApiMutation({
|
|
90
|
-
errorMessage: "Failed to save feature flags.",
|
|
91
|
-
mutationFn: async () => {
|
|
92
|
-
await apiClient.put(ADMIN_ENDPOINTS.FEATURE_FLAGS, { flags, rollouts });
|
|
93
|
-
},
|
|
94
|
-
onSuccess: async () => {
|
|
95
|
-
await queryClient.invalidateQueries({ queryKey: ["admin", "feature-flags"] });
|
|
96
|
-
showToast("Feature flags saved.", "success");
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
const defaultFlags = () => (_jsxs(Form, { schema: featureFlagsUpdateSchema, onSubmit: (event) => {
|
|
100
|
-
event.preventDefault();
|
|
101
|
-
saveFlags.mutate();
|
|
102
|
-
}, spacing: "md", children: [_jsx(FormErrorSummary, {}), _jsx(AccordionSection, { title: "Platform Features", children: PLATFORM_FLAGS.map(({ key, label, desc }) => (_jsx(FlagRow, { label: label, desc: desc, checked: getPlatformFlag(key), onChange: (val) => setPlatformFlag(key, val), rollout: rollouts[key], onRolloutChange: (val) => setRollouts((prev) => ({ ...prev, [key]: val })), showRollout: true }, key))) }), _jsx(AccordionSection, { title: "Listing Types", children: LISTING_TYPE_FLAGS.map(({ key, label, desc }) => (_jsx(FlagRow, { label: label, desc: desc, checked: getListingTypeFlag(key), onChange: (val) => setListingTypeFlag(key, val), showRollout: false }, key))) }), _jsx(AccordionSection, { title: "Category Types", children: CATEGORY_TYPE_FLAGS.map(({ key, label, desc }) => (_jsx(FlagRow, { label: label, desc: desc, checked: getCategoryTypeFlag(key), onChange: (val) => setCategoryTypeFlag(key, val), showRollout: false }, key))) }), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: () => {
|
|
103
|
-
setFlags(data?.flags ?? {});
|
|
104
|
-
setRollouts(data?.rollouts ?? {});
|
|
105
|
-
}, disabled: saveFlags.isPending, children: "Reset" }), _jsx(Button, { type: "submit", isLoading: saveFlags.isPending, disabled: saveFlags.isPending, children: "Save All Flags" })] })] }));
|
|
106
|
-
const loadingAlert = isLoading ? (_jsx(Alert, { variant: "info", title: "Loading feature flags", children: "Fetching feature flags\u2026" })) : null;
|
|
107
|
-
const errorAlert = error ? (_jsx(Alert, { variant: "error", title: "Could not load feature flags", children: error instanceof Error ? error.message : "Unknown error" })) : null;
|
|
108
|
-
return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: labels.title ?? "Feature Flags", sections: [loadingAlert, errorAlert, renderFlags?.() ?? defaultFlags()] }));
|
|
109
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { StackedViewShellProps } from "../../../ui";
|
|
3
|
-
export interface AdminSiteViewProps extends Omit<StackedViewShellProps, "sections"> {
|
|
4
|
-
labels?: {
|
|
5
|
-
title?: string;
|
|
6
|
-
};
|
|
7
|
-
renderTabs?: () => React.ReactNode;
|
|
8
|
-
renderForm?: () => React.ReactNode;
|
|
9
|
-
}
|
|
10
|
-
export declare function AdminSiteView({ labels, renderTabs, renderForm, ...rest }: AdminSiteViewProps): React.JSX.Element;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Button, Form, FormActions, Input, StackedViewShell, Toggle, } from "../../../ui";
|
|
7
|
-
import { useSiteSettings } from "../../../core/hooks/useSiteSettings";
|
|
8
|
-
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
|
-
import { apiClient } from "../../../http";
|
|
10
|
-
import { announcementBarSchema } from "../schemas/admin-editor-forms";
|
|
11
|
-
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
|
|
12
|
-
export function AdminSiteView({ labels = {}, renderTabs, renderForm, ...rest }) {
|
|
13
|
-
const queryClient = useQueryClient();
|
|
14
|
-
const { data, isLoading, error } = useSiteSettings();
|
|
15
|
-
const [announcementEnabled, setAnnouncementEnabled] = React.useState(true);
|
|
16
|
-
const [announcementMessage, setAnnouncementMessage] = React.useState("");
|
|
17
|
-
const [saveMessage, setSaveMessage] = React.useState(null);
|
|
18
|
-
React.useEffect(() => {
|
|
19
|
-
if (!data)
|
|
20
|
-
return;
|
|
21
|
-
setAnnouncementEnabled(data.announcementBar?.enabled ?? true);
|
|
22
|
-
setAnnouncementMessage(data.announcementBar?.message ?? "");
|
|
23
|
-
}, [data]);
|
|
24
|
-
const saveAnnouncement = useApiMutation({
|
|
25
|
-
mutationFn: async () => {
|
|
26
|
-
// Writes go to the admin endpoint. `PATCH /api/site-settings` was
|
|
27
|
-
// removed — that route is public-read-only now. The READ above still
|
|
28
|
-
// uses the public endpoint, which is fine: `announcementBar` is in its
|
|
29
|
-
// allow-list.
|
|
30
|
-
await apiClient.put(ADMIN_ENDPOINTS.ADMIN_SITE, {
|
|
31
|
-
announcementBar: {
|
|
32
|
-
enabled: announcementEnabled,
|
|
33
|
-
message: announcementMessage,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
onSuccess: async () => {
|
|
38
|
-
await queryClient.invalidateQueries({ queryKey: ["site-settings"] });
|
|
39
|
-
setSaveMessage("Announcement settings saved.");
|
|
40
|
-
},
|
|
41
|
-
onError: () => {
|
|
42
|
-
setSaveMessage("Failed to save announcement settings.");
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
const defaultForm = () => (_jsxs(Form, { schema: announcementBarSchema, onSubmit: (event) => {
|
|
46
|
-
event.preventDefault();
|
|
47
|
-
saveAnnouncement.mutate();
|
|
48
|
-
}, spacing: "md", children: [_jsx(FormErrorSummary, {}), _jsx(Toggle, { checked: announcementEnabled, onChange: setAnnouncementEnabled, label: "Show announcement bar on homepage" }), _jsx(Input, { label: "Announcement message", value: announcementMessage, onChange: (event) => setAnnouncementMessage(event.target.value), placeholder: "Enter homepage announcement", disabled: !announcementEnabled, helperText: "This message is shown at the top of the homepage when enabled." }), _jsx(FormActions, { align: "right", children: _jsx(Button, { type: "submit", disabled: saveAnnouncement.isPending || (announcementEnabled && !announcementMessage.trim()), children: saveAnnouncement.isPending ? "Saving..." : "Save announcement" }) }), saveMessage ? (_jsx(Alert, { variant: saveMessage.startsWith("Failed") ? "error" : "success", title: saveMessage.startsWith("Failed") ? "Save failed" : "Saved", children: saveMessage })) : null] }));
|
|
49
|
-
const loadingAlert = isLoading ? (_jsx(Alert, { variant: "info", title: "Loading settings", children: "Fetching site settings..." })) : null;
|
|
50
|
-
const errorAlert = error ? (_jsx(Alert, { variant: "error", title: "Could not load settings", children: error instanceof Error ? error.message : "Unknown error" })) : null;
|
|
51
|
-
return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: labels.title ?? "Site Settings", sections: [renderTabs?.(), loadingAlert, errorAlert, renderForm?.() ?? defaultForm()] }));
|
|
52
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type IClientRealtimeProvider } from "../../../contracts/client-realtime";
|
|
2
|
-
export interface ChatMessage {
|
|
3
|
-
id: string;
|
|
4
|
-
userId: string;
|
|
5
|
-
userName: string;
|
|
6
|
-
message: string;
|
|
7
|
-
timestamp: number;
|
|
8
|
-
}
|
|
9
|
-
export interface UseChatReturn {
|
|
10
|
-
messages: ChatMessage[];
|
|
11
|
-
sendMessage: (text: string) => Promise<void>;
|
|
12
|
-
isConnected: boolean;
|
|
13
|
-
isLoading: boolean;
|
|
14
|
-
error: string | null;
|
|
15
|
-
}
|
|
16
|
-
export declare function useChat(chatId: string | null, options?: {
|
|
17
|
-
realtimeProvider?: IClientRealtimeProvider;
|
|
18
|
-
}): UseChatReturn;
|
|
19
|
-
export declare function useChatRooms(): import("@tanstack/react-query").UseQueryResult<unknown[], Error>;
|
|
20
|
-
export declare function useCreateChatRoom(): import("@tanstack/react-query").UseMutationResult<unknown, import("@mohasinac/appkit/client").ApiError, {
|
|
21
|
-
orderId: string;
|
|
22
|
-
ownerId: string;
|
|
23
|
-
}, unknown>;
|
|
24
|
-
export declare function useDeleteChatRoom(): import("@tanstack/react-query").UseMutationResult<import("@mohasinac/appkit/client").JsonValue, import("@mohasinac/appkit/client").ApiError, string, unknown>;
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { normalizeError } from "../../../errors/normalize";
|
|
3
|
-
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
|
-
import { useEffect, useState, useCallback, useRef } from "react";
|
|
5
|
-
import { useQuery } from "@tanstack/react-query";
|
|
6
|
-
import { getClientRealtimeProvider, } from "../../../contracts/client-realtime";
|
|
7
|
-
import { logger } from "../../../core/Logger";
|
|
8
|
-
import { apiClient } from "../../../http";
|
|
9
|
-
import { nowMs } from "../../../utils";
|
|
10
|
-
import { ADMIN_ENDPOINTS, CHAT_ENDPOINTS, } from "../../../constants/api-endpoints";
|
|
11
|
-
export function useChat(chatId, options) {
|
|
12
|
-
const [messages, setMessages] = useState([]);
|
|
13
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
14
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
15
|
-
const [error, setError] = useState(null);
|
|
16
|
-
const tokenExpiresAtRef = useRef(0);
|
|
17
|
-
const unsubscribeRef = useRef(null);
|
|
18
|
-
const connectAndSubscribe = useCallback(async () => {
|
|
19
|
-
if (!chatId)
|
|
20
|
-
return;
|
|
21
|
-
setIsLoading(true);
|
|
22
|
-
setError(null);
|
|
23
|
-
const provider = options?.realtimeProvider ?? getClientRealtimeProvider();
|
|
24
|
-
try {
|
|
25
|
-
const shouldRefresh = !tokenExpiresAtRef.current ||
|
|
26
|
-
tokenExpiresAtRef.current - nowMs() < 60000;
|
|
27
|
-
if (shouldRefresh) {
|
|
28
|
-
const tokenResponse = await apiClient.post(ADMIN_ENDPOINTS.REALTIME_TOKEN, {});
|
|
29
|
-
await provider.signInWithToken(tokenResponse.customToken);
|
|
30
|
-
tokenExpiresAtRef.current = tokenResponse.expiresAt;
|
|
31
|
-
}
|
|
32
|
-
if (unsubscribeRef.current) {
|
|
33
|
-
unsubscribeRef.current();
|
|
34
|
-
unsubscribeRef.current = null;
|
|
35
|
-
}
|
|
36
|
-
unsubscribeRef.current = provider.subscribe(`/chat/${chatId}/messages`, (snapshot) => {
|
|
37
|
-
if (snapshot.exists()) {
|
|
38
|
-
const raw = snapshot.val();
|
|
39
|
-
const parsed = Object.entries(raw)
|
|
40
|
-
.map(([id, msg]) => ({ id, ...msg }))
|
|
41
|
-
.sort((a, b) => a.timestamp - b.timestamp);
|
|
42
|
-
setMessages(parsed);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
setMessages([]);
|
|
46
|
-
}
|
|
47
|
-
setIsConnected(true);
|
|
48
|
-
setIsLoading(false);
|
|
49
|
-
}, (err) => {
|
|
50
|
-
logger.error("Chat RTDB subscription error", err);
|
|
51
|
-
setError("Could not connect to chat. Please try again.");
|
|
52
|
-
setIsConnected(false);
|
|
53
|
-
setIsLoading(false);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
void normalizeError(err);
|
|
58
|
-
logger.error("Failed to authenticate for chat RTDB", err);
|
|
59
|
-
setError("Failed to connect to chat.");
|
|
60
|
-
setIsLoading(false);
|
|
61
|
-
}
|
|
62
|
-
}, [chatId, options?.realtimeProvider]);
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
connectAndSubscribe();
|
|
65
|
-
return () => {
|
|
66
|
-
if (unsubscribeRef.current) {
|
|
67
|
-
unsubscribeRef.current();
|
|
68
|
-
unsubscribeRef.current = null;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}, [connectAndSubscribe]);
|
|
72
|
-
const sendMessage = useCallback(async (text) => {
|
|
73
|
-
if (!chatId || !text.trim())
|
|
74
|
-
return;
|
|
75
|
-
await apiClient.post(CHAT_ENDPOINTS.MESSAGES(chatId), {
|
|
76
|
-
message: text.trim(),
|
|
77
|
-
});
|
|
78
|
-
}, [chatId]);
|
|
79
|
-
return { messages, sendMessage, isConnected, isLoading, error };
|
|
80
|
-
}
|
|
81
|
-
export function useChatRooms() {
|
|
82
|
-
return useQuery({
|
|
83
|
-
queryKey: ["chat", "rooms"],
|
|
84
|
-
queryFn: () => apiClient
|
|
85
|
-
.get(CHAT_ENDPOINTS.LIST)
|
|
86
|
-
.then((r) => r.rooms),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
export function useCreateChatRoom() {
|
|
90
|
-
return useApiMutation({
|
|
91
|
-
mutationFn: (data) => apiClient
|
|
92
|
-
.post(CHAT_ENDPOINTS.LIST, data)
|
|
93
|
-
.then((r) => r.room),
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
export function useDeleteChatRoom() {
|
|
97
|
-
return useApiMutation({
|
|
98
|
-
mutationFn: (chatId) => apiClient.delete(CHAT_ENDPOINTS.BY_ID(chatId)),
|
|
99
|
-
});
|
|
100
|
-
}
|