@mohasinac/appkit 2.4.0 → 2.4.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/client.d.ts CHANGED
@@ -129,3 +129,7 @@ export type { PromotionsViewProductSectionProps } from "./features/promotions/co
129
129
  export { RichText } from "./ui/rich-text/RichText";
130
130
  export { RichTextRenderer } from "./ui/rich-text/RichTextRenderer";
131
131
  export type { RichTextRendererProps } from "./ui/rich-text/RichTextRenderer";
132
+ export { SCAM_TYPES, SCAM_CATEGORIES, SCAM_TYPE_LABELS, SCAM_CATEGORY_LABELS, getScamType, getScamTypesByCategory, } from "./features/scams/constants/scam-types";
133
+ export type { ScamType, ScamCategory, ScamTypeDefinition, ScamCategoryDefinition } from "./features/scams/constants/scam-types";
134
+ export { SCAM_PLATFORM_LABELS, ScamPlatformValues, } from "./features/scams/schemas/firestore";
135
+ export type { ScamPlatform } from "./features/scams/schemas/firestore";
package/dist/client.js CHANGED
@@ -160,3 +160,6 @@ export { EventDetailView } from "./features/events/components/index";
160
160
  export { PromotionsViewProductSection, PromotionsHero, PromotionsView } from "./features/promotions/components/index";
161
161
  export { RichText } from "./ui/rich-text/RichText";
162
162
  export { RichTextRenderer } from "./ui/rich-text/RichTextRenderer";
163
+ // Scam registry — pure data constants safe for client bundle
164
+ export { SCAM_TYPES, SCAM_CATEGORIES, SCAM_TYPE_LABELS, SCAM_CATEGORY_LABELS, getScamType, getScamTypesByCategory, } from "./features/scams/constants/scam-types";
165
+ export { SCAM_PLATFORM_LABELS, ScamPlatformValues, } from "./features/scams/schemas/firestore";
@@ -1,7 +1,10 @@
1
- import type { ScammerDocument } from "../schemas/firestore";
1
+ import type { ScammerDocument, ScammerIncidentDocument, ScammerCommentDocument } from "../schemas/firestore";
2
2
  export interface ScamProfileViewProps {
3
3
  scammer: ScammerDocument;
4
4
  /** When true the contest/report buttons are direct links; otherwise show sign-in prompts. */
5
5
  isAuthenticated: boolean;
6
+ incidents?: ScammerIncidentDocument[];
7
+ comments?: ScammerCommentDocument[];
8
+ relatedScammers?: ScammerDocument[];
6
9
  }
7
- export declare function ScamProfileView({ scammer, isAuthenticated }: ScamProfileViewProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function ScamProfileView({ scammer, isAuthenticated, incidents, comments, relatedScammers, }: ScamProfileViewProps): import("react/jsx-runtime").JSX.Element;
@@ -30,7 +30,7 @@ function statusVariant(status) {
30
30
  return "warning";
31
31
  return "inactive";
32
32
  }
33
- export function ScamProfileView({ scammer, isAuthenticated }) {
33
+ export function ScamProfileView({ scammer, isAuthenticated, incidents = [], comments = [], relatedScammers = [], }) {
34
34
  const reportHref = String(ROUTES.PUBLIC.SCAM_REPORT);
35
35
  const registryHref = String(ROUTES.PUBLIC.SCAMS);
36
36
  const contestLoginHref = `${String(ROUTES.AUTH.LOGIN)}?redirect=${encodeURIComponent(`/scams/${scammer.id}`)}`;
@@ -45,5 +45,7 @@ export function ScamProfileView({ scammer, isAuthenticated }) {
45
45
  if (!scamTypeDef || scamTypeDef.howToAvoid.length === 0)
46
46
  return null;
47
47
  return (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "How to Avoid This Scam" }), _jsx(Card, { variant: "flat", padding: "md", children: _jsx(Stack, { gap: "xs", as: "ol", children: scamTypeDef.howToAvoid.map((tip, i) => (_jsxs(Row, { gap: "sm", align: "start", as: "li", children: [_jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[color:var(--appkit-color-success,theme(colors.green.600))]/10 text-xs font-bold text-[color:var(--appkit-color-success,theme(colors.green.700))]", children: i + 1 }), _jsx(Text, { variant: "secondary", className: "text-sm leading-relaxed", children: tip })] }, i))) }) })] }));
48
- })(), scammer.evidence.length > 0 && (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Evidence" }), _jsx(Row, { gap: "sm", wrap: true, children: scammer.evidence.map((url, i) => (_jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", children: _jsx("img", { src: url, alt: `Evidence ${i + 1}`, className: "h-32 w-auto rounded-lg border object-cover shadow-sm hover:opacity-90" }) }, i))) })] })), _jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Additional Incidents" }), _jsx(EmptyState, { icon: _jsx(FileText, { className: "h-8 w-8" }), title: "No additional incidents yet", description: "Other victims' reports linked to this profile will appear here once verified." })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Community Discussion" }), _jsx(EmptyState, { icon: _jsx(MessageSquare, { className: "h-8 w-8" }), title: "No comments yet", description: "Comments and victim testimonials will appear here." })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Related Profiles" }), _jsx(EmptyState, { icon: _jsx(Link2, { className: "h-8 w-8" }), title: "No related profiles", description: "Other scammer profiles linked to this person will appear here." })] })] }), _jsxs(Stack, { gap: "md", children: [_jsxs(Card, { variant: "elevated", padding: "md", children: [_jsx(CardHeader, { children: _jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide", children: "Actions" }) }), _jsx(CardBody, { children: _jsxs(Stack, { gap: "sm", children: [isAuthenticated ? (_jsxs(Link, { href: reportHref, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(AlertOctagon, { className: "h-4 w-4 text-[color:var(--appkit-color-danger,theme(colors.red.500))]" }), "Report another incident"] })) : (_jsxs(Link, { href: `${String(ROUTES.AUTH.LOGIN)}?redirect=${encodeURIComponent(reportHref)}`, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(AlertOctagon, { className: "h-4 w-4 text-[color:var(--appkit-color-danger,theme(colors.red.500))]" }), "Sign in to report an incident"] })), isAuthenticated ? (_jsxs(Link, { href: `/scams/${scammer.id}/contest`, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(Flag, { className: "h-4 w-4 text-[color:var(--appkit-color-warning,theme(colors.amber.500))]" }), "Contest this profile"] })) : (_jsxs(Link, { href: contestLoginHref, className: "appkit-button appkit-button--ghost appkit-button--md flex w-full items-center gap-2", children: [_jsx(Flag, { className: "h-4 w-4" }), "Sign in to contest"] })), _jsx(Text, { variant: "secondary", className: "text-xs", children: "All contest submissions are reviewed by our moderation team before any changes are made." })] }) })] }), _jsxs(Card, { variant: "outlined", padding: "md", children: [_jsx(CardHeader, { children: _jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide", children: "Contest Options" }) }), _jsx(CardBody, { children: _jsx(Stack, { gap: "xs", as: "ul", children: Object.entries(CONTEST_TYPE_LABELS).map(([, label]) => (_jsxs(Row, { gap: "sm", align: "start", as: "li", children: [_jsx("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-[color:var(--appkit-color-border,theme(colors.zinc.300))]" }), _jsx(Text, { variant: "secondary", className: "text-xs", children: label })] }, label))) }) })] }), scammer.verifiedAt && (_jsx(Alert, { variant: "success", compact: true, children: _jsxs(Row, { gap: "xs", align: "center", children: [_jsx(Shield, { className: "h-3.5 w-3.5 shrink-0" }), _jsxs(Text, { className: "text-xs font-medium", children: ["Verified by LetItRip moderation on ", formatDate(scammer.verifiedAt)] })] }) }))] })] }) }) })] }));
48
+ })(), scammer.evidence.length > 0 && (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Evidence" }), _jsx(Row, { gap: "sm", wrap: true, children: scammer.evidence.map((url, i) => (_jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", children: _jsx("img", { src: url, alt: `Evidence ${i + 1}`, className: "h-32 w-auto rounded-lg border object-cover shadow-sm hover:opacity-90" }) }, i))) })] })), _jsxs(Stack, { gap: "sm", children: [_jsx(Row, { justify: "between", align: "center", children: _jsxs(Heading, { level: 2, className: "text-base font-semibold", children: ["Additional Incidents", incidents.length > 0 && ` (${incidents.length})`] }) }), incidents.length === 0 ? (_jsx(EmptyState, { icon: _jsx(FileText, { className: "h-8 w-8" }), title: "No additional incidents yet", description: "Other victims' verified reports linked to this profile will appear here." })) : (_jsx(Stack, { gap: "sm", children: incidents.map((inc) => (_jsx(Card, { variant: "outlined", padding: "md", children: _jsxs(Stack, { gap: "xs", children: [_jsxs(Row, { justify: "between", align: "start", gap: "sm", className: "flex-wrap", children: [_jsxs(Row, { gap: "xs", wrap: true, children: [_jsx(Badge, { variant: "warning", children: SCAM_TYPE_LABELS[inc.scamType] ?? inc.scamType }), _jsxs(Badge, { variant: "default", children: ["via ", SCAM_PLATFORM_LABELS[inc.scamPlatform] ?? inc.scamPlatform] })] }), _jsx(Text, { variant: "secondary", className: "text-xs", children: formatDate(inc.createdAt) })] }), inc.itemInvolved && (_jsxs(Text, { variant: "secondary", className: "text-xs", children: ["Item: ", inc.itemInvolved] })), inc.amountLost ? (_jsxs(Text, { className: "text-xs font-medium text-[color:var(--appkit-color-danger,theme(colors.red.600))]", children: [formatPaise(inc.amountLost), " lost"] })) : null, _jsx(Text, { variant: "secondary", className: "text-sm leading-relaxed", children: inc.description.length > 200
49
+ ? `${inc.description.slice(0, 200).trimEnd()}…`
50
+ : inc.description }), _jsxs(Text, { variant: "secondary", className: "text-xs", children: ["Reported by: ", inc.reportedByAnon ? "Anonymous" : "Verified victim"] })] }) }, inc.id))) }))] }), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Heading, { level: 2, className: "text-base font-semibold", children: ["Community Discussion", comments.length > 0 && ` (${comments.length})`] }), isAuthenticated ? (_jsx(Link, { href: String(ROUTES.PUBLIC.SCAM_REPORT), className: "text-xs text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "Leave a comment" })) : (_jsx(Link, { href: `${String(ROUTES.AUTH.LOGIN)}?redirect=${encodeURIComponent(`/scams/${scammer.id}`)}`, className: "text-xs text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "Sign in to comment" }))] }), comments.length === 0 ? (_jsx(EmptyState, { icon: _jsx(MessageSquare, { className: "h-8 w-8" }), title: "No comments yet", description: "Community comments and victim testimonials appear here." })) : (_jsx(Stack, { gap: "sm", children: comments.map((c) => (_jsx(Card, { variant: "flat", padding: "md", children: _jsxs(Stack, { gap: "xs", children: [_jsxs(Row, { justify: "between", align: "center", gap: "sm", children: [_jsxs(Row, { gap: "xs", align: "center", children: [_jsx(Text, { className: "text-sm font-medium", children: c.authorDisplayName }), c.authorRole !== "user" && (_jsx(Badge, { variant: "default", className: "text-[10px]", children: c.authorRole })), c.isAccused && c.isAccusedVerified && (_jsx(Badge, { variant: "warning", className: "text-[10px]", children: "Accused" })), c.isVerifiedVictim && (_jsx(Badge, { variant: "success", className: "text-[10px]", children: "Verified Victim" }))] }), _jsx(Text, { variant: "secondary", className: "text-xs", children: formatDate(c.createdAt) })] }), _jsx(Text, { variant: "secondary", className: "text-sm leading-relaxed", children: c.body })] }) }, c.id))) }))] }), relatedScammers.length > 0 && (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold", children: "Related Profiles" }), _jsx(Stack, { gap: "sm", children: relatedScammers.map((rel) => (_jsx(Link, { href: String(ROUTES.PUBLIC.SCAM_DETAIL(rel.id)), className: "block", children: _jsx(Card, { variant: "outlined", padding: "sm", className: "hover:opacity-80 transition-opacity", children: _jsxs(Row, { gap: "sm", align: "center", justify: "between", children: [_jsxs(Stack, { gap: "none", children: [_jsx(Text, { className: "text-sm font-medium", children: rel.displayNames[0] }), _jsx(Text, { variant: "secondary", className: "text-xs", children: SCAM_TYPE_LABELS[rel.scamType] ?? rel.scamType })] }), _jsxs(Row, { gap: "xs", align: "center", children: [_jsx(Badge, { variant: statusVariant(rel.status), children: SCAMMER_STATUS_LABELS[rel.status] ?? rel.status }), _jsx(Link2, { className: "h-4 w-4 text-[color:var(--appkit-color-text-muted,theme(colors.zinc.400))]" })] })] }) }) }, rel.id))) })] }))] }), _jsxs(Stack, { gap: "md", children: [_jsxs(Card, { variant: "elevated", padding: "md", children: [_jsx(CardHeader, { children: _jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide", children: "Actions" }) }), _jsx(CardBody, { children: _jsxs(Stack, { gap: "sm", children: [isAuthenticated ? (_jsxs(Link, { href: reportHref, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(AlertOctagon, { className: "h-4 w-4 text-[color:var(--appkit-color-danger,theme(colors.red.500))]" }), "Report another incident"] })) : (_jsxs(Link, { href: `${String(ROUTES.AUTH.LOGIN)}?redirect=${encodeURIComponent(reportHref)}`, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(AlertOctagon, { className: "h-4 w-4 text-[color:var(--appkit-color-danger,theme(colors.red.500))]" }), "Sign in to report an incident"] })), isAuthenticated ? (_jsxs(Link, { href: `/scams/${scammer.id}/contest`, className: "appkit-button appkit-button--outline appkit-button--md flex w-full items-center gap-2", children: [_jsx(Flag, { className: "h-4 w-4 text-[color:var(--appkit-color-warning,theme(colors.amber.500))]" }), "Contest this profile"] })) : (_jsxs(Link, { href: contestLoginHref, className: "appkit-button appkit-button--ghost appkit-button--md flex w-full items-center gap-2", children: [_jsx(Flag, { className: "h-4 w-4" }), "Sign in to contest"] })), _jsx(Text, { variant: "secondary", className: "text-xs", children: "All contest submissions are reviewed by our moderation team before any changes are made." })] }) })] }), _jsxs(Card, { variant: "outlined", padding: "md", children: [_jsx(CardHeader, { children: _jsx(Heading, { level: 3, className: "text-sm font-semibold uppercase tracking-wide", children: "Contest Options" }) }), _jsx(CardBody, { children: _jsx(Stack, { gap: "xs", as: "ul", children: Object.entries(CONTEST_TYPE_LABELS).map(([, label]) => (_jsxs(Row, { gap: "sm", align: "start", as: "li", children: [_jsx("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-[color:var(--appkit-color-border,theme(colors.zinc.300))]" }), _jsx(Text, { variant: "secondary", className: "text-xs", children: label })] }, label))) }) })] }), scammer.verifiedAt && (_jsx(Alert, { variant: "success", compact: true, children: _jsxs(Row, { gap: "xs", align: "center", children: [_jsx(Shield, { className: "h-3.5 w-3.5 shrink-0" }), _jsxs(Text, { className: "text-xs font-medium", children: ["Verified by LetItRip moderation on ", formatDate(scammer.verifiedAt)] })] }) }))] })] }) }) })] }));
49
51
  }
package/dist/index.d.ts CHANGED
@@ -528,6 +528,7 @@ export { siteSettingsRepository } from "./repositories/index";
528
528
  export { smsCounterRepository } from "./repositories/index";
529
529
  export { storeAddressRepository } from "./repositories/index";
530
530
  export { storeRepository } from "./repositories/index";
531
+ export { scammerRepository } from "./repositories/index";
531
532
  export { tokenRepository } from "./repositories/index";
532
533
  export { userRepository } from "./repositories/index";
533
534
  export { wishlistRepository } from "./repositories/index";
@@ -2899,7 +2900,8 @@ export { ScamRegistryView } from "./features/scams/components/ScamRegistryView";
2899
2900
  export type { ScamRegistryViewProps } from "./features/scams/components/ScamRegistryView";
2900
2901
  export { ScamProfileView } from "./features/scams/components/ScamProfileView";
2901
2902
  export type { ScamProfileViewProps } from "./features/scams/components/ScamProfileView";
2902
- export { listVerifiedScammers, getPublicScammerById } from "./features/scams/actions/scam-actions";
2903
+ export { listVerifiedScammers, getPublicScammerById, getScammerProfilePageData, } from "./features/scams/actions/scam-actions";
2904
+ export type { ScammerProfilePageData } from "./features/scams/actions/scam-actions";
2903
2905
  export type { ScammerListResult } from "./features/scams/actions/scam-actions";
2904
2906
  export { SellerProductShell } from "./features/seller/components/SellerProductShell";
2905
2907
  export type { SellerProductShellProps, SellerProductDraft, ProductListingMode } from "./features/seller/components/SellerProductShell";
package/dist/index.js CHANGED
@@ -1079,6 +1079,9 @@ export { storeAddressRepository } from "./repositories/index";
1079
1079
  // storeRepository - Shared export for store repository.
1080
1080
  export { storeRepository } from "./repositories/index";
1081
1081
  // [DB]-Database layer — uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
1082
+ // scammerRepository - Shared export for scammer profiles repository.
1083
+ export { scammerRepository } from "./repositories/index";
1084
+ // [DB]-Database layer — uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
1082
1085
  // tokenRepository - Shared export for token repository.
1083
1086
  export { tokenRepository } from "./repositories/index";
1084
1087
  // [DB]-Database layer — uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
@@ -5331,7 +5334,7 @@ export { SCAM_TYPES, SCAM_CATEGORIES, SCAM_TYPE_LABELS, SCAM_CATEGORY_LABELS, ge
5331
5334
  export { ScamRegistryView } from "./features/scams/components/ScamRegistryView";
5332
5335
  export { ScamProfileView } from "./features/scams/components/ScamProfileView";
5333
5336
  // Scam server actions
5334
- export { listVerifiedScammers, getPublicScammerById } from "./features/scams/actions/scam-actions";
5337
+ export { listVerifiedScammers, getPublicScammerById, getScammerProfilePageData, } from "./features/scams/actions/scam-actions";
5335
5338
  // --- Shell primitives (UX1/UX2/UX3/UX6) ----------------------------------------
5336
5339
  // [CLIENT] SellerProductShell — full-flow create/edit shell for standard, auction, and pre-order listings.
5337
5340
  export { SellerProductShell } from "./features/seller/components/SellerProductShell";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"