@fayz-ai/plugin-reputation 0.9.4 → 0.10.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/README.md +30 -5
- package/dist/chunk-BGCEG4NA.js +410 -0
- package/dist/chunk-BGCEG4NA.js.map +1 -0
- package/dist/components/ProductRating.d.ts +15 -0
- package/dist/components/ProductRating.d.ts.map +1 -0
- package/dist/components/ProductReviews.d.ts +12 -0
- package/dist/components/ProductReviews.d.ts.map +1 -0
- package/dist/components/Stars.d.ts +15 -0
- package/dist/components/Stars.d.ts.map +1 -0
- package/dist/components/TopReviews.d.ts +13 -0
- package/dist/components/TopReviews.d.ts.map +1 -0
- package/dist/data/index.d.ts +4 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/mock.d.ts +2 -0
- package/dist/data/mock.d.ts.map +1 -1
- package/dist/data/registries.d.ts +3 -0
- package/dist/data/registries.d.ts.map +1 -0
- package/dist/data/supabase.d.ts +5 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/tables.d.ts +8 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/data/types.d.ts +24 -3
- package/dist/data/types.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useManagedReviews.d.ts +23 -0
- package/dist/hooks/useManagedReviews.d.ts.map +1 -0
- package/dist/hooks/useProductReviews.d.ts +23 -0
- package/dist/hooks/useProductReviews.d.ts.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +238 -48
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.d.ts +6 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/public/index.d.ts +14 -2
- package/dist/public/index.d.ts.map +1 -1
- package/dist/public/index.js +295 -84
- package/dist/public/index.js.map +1 -1
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/views/ReputationHome.d.ts.map +1 -1
- package/package.json +8 -6
package/dist/public/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data/mock.ts","../../src/data/supabase.ts","../../src/context.tsx","../../src/hooks/useReviews.ts","../../src/hooks/useReviewSummary.ts","../../src/components/ReviewsList.tsx","../../src/public/index.tsx"],"names":["useState","useEffect","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReputationDataProvider } from './types'\nimport type { Review, ReviewSummary, ReviewListQuery } from '../types'\n\nexport interface ReputationSeed {\n reviews: Review[]\n /** Explicit aggregate. If omitted, it is computed from `reviews`. */\n summary?: ReviewSummary\n}\n\nexport interface MockReputationProviderOptions {\n seed?: ReputationSeed\n}\n\nconst FALLBACK_REVIEWS: Review[] = [\n { id: 'r1', author: 'Camila R.', source: 'Google', rating: 5, text: 'Excelente atendimento, recomendo!', date: 'Jun 2025' },\n { id: 'r2', author: 'Tom B.', source: 'Facebook', rating: 5, text: 'Processo simples e resultado ótimo.', date: 'Jun 2025' },\n { id: 'r3', author: 'Aisha K.', source: 'Google', rating: 4, text: 'Muito bom no geral.', date: 'Jun 2025' },\n]\n\nfunction computeSummary(reviews: Review[]): ReviewSummary {\n const count = reviews.length\n const average = count === 0 ? 0 : Math.round((reviews.reduce((s, r) => s + r.rating, 0) / count) * 10) / 10\n const distribution = [5, 4, 3, 2, 1].map((stars) => ({\n stars,\n count: reviews.filter((r) => Math.round(r.rating) === stars).length,\n }))\n return { average, count, distribution }\n}\n\nexport function createMockReputationProvider(options?: MockReputationProviderOptions): ReputationDataProvider {\n const reviews: Review[] = options?.seed?.reviews ?? FALLBACK_REVIEWS\n const summary: ReviewSummary = options?.seed?.summary ?? computeSummary(reviews)\n\n return {\n async listReviews(query?: ReviewListQuery): Promise<Review[]> {\n let result = reviews\n if (query?.minRating != null) result = result.filter((r) => r.rating >= query.minRating!)\n if (query?.limit != null) result = result.slice(0, query.limit)\n return result\n },\n async getSummary(): Promise<ReviewSummary> {\n return summary\n },\n }\n}\n","import type { ReputationDataProvider } from './types'\nimport type { Review, ReviewSummary, ReviewListQuery } from '../types'\n\n// ---------------------------------------------------------------------------\n// Supabase-backed reputation provider — STUB (deferred to Phase 2).\n//\n// Later: read a `reviews` table (tenant-scoped, RLS) and/or synced Google/\n// Facebook reviews. Swapping this in is a pure provider change — hooks and\n// components are untouched. Throws until then so createSafeDataProvider falls\n// back to the mock/seed provider whenever no Supabase client is configured.\n// ---------------------------------------------------------------------------\n\nexport function createSupabaseReputationProvider(): ReputationDataProvider {\n const notImplemented = (): never => {\n throw new Error(\n '[plugin-reputation] Supabase provider not implemented yet — deferred to Phase 2. ' +\n 'Run on the mock/seed provider (no Supabase client configured) for now.',\n )\n }\n return {\n listReviews: (_query?: ReviewListQuery): Promise<Review[]> => notImplemented(),\n getSummary: (): Promise<ReviewSummary> => notImplemented(),\n }\n}\n","import { createContext, useContext, type ReactNode } from 'react'\nimport type { ReputationDataProvider } from './data/types'\n\nexport interface ReputationContextValue {\n provider: ReputationDataProvider\n}\n\nconst ReputationContext = createContext<ReputationContextValue | null>(null)\n\nexport function ReputationProvider({ value, children }: { value: ReputationContextValue; children: ReactNode }) {\n return <ReputationContext.Provider value={value}>{children}</ReputationContext.Provider>\n}\n\nexport function useReputationContext(): ReputationContextValue {\n const ctx = useContext(ReputationContext)\n if (!ctx) {\n throw new Error('[plugin-reputation] useReputationContext must be used within <ReputationProvider>.')\n }\n return ctx\n}\n","import { useEffect, useState } from 'react'\nimport { useReputationContext } from '../context'\nimport type { Review, ReviewListQuery } from '../types'\n\nexport interface UseReviewsResult {\n reviews: Review[]\n loading: boolean\n error: Error | null\n}\n\n/** Fetch the review list from the active reputation provider. */\nexport function useReviews(query?: ReviewListQuery): UseReviewsResult {\n const { provider } = useReputationContext()\n const [reviews, setReviews] = useState<Review[]>([])\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const limit = query?.limit\n const minRating = query?.minRating\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider\n .listReviews({ limit, minRating })\n .then((result) => {\n if (!active) return\n setReviews(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider, limit, minRating])\n\n return { reviews, loading, error }\n}\n","import { useEffect, useState } from 'react'\nimport { useReputationContext } from '../context'\nimport type { ReviewSummary } from '../types'\n\nexport interface UseReviewSummaryResult {\n summary: ReviewSummary | null\n loading: boolean\n error: Error | null\n}\n\n/** Fetch the aggregate rating summary (average + count + distribution). */\nexport function useReviewSummary(): UseReviewSummaryResult {\n const { provider } = useReputationContext()\n const [summary, setSummary] = useState<ReviewSummary | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider\n .getSummary()\n .then((result) => {\n if (!active) return\n setSummary(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider])\n\n return { summary, loading, error }\n}\n","import { Star } from 'lucide-react'\nimport { useReviews } from '../hooks/useReviews'\nimport { useReviewSummary } from '../hooks/useReviewSummary'\n\nfunction Stars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5\">\n {[1, 2, 3, 4, 5].map((i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i <= rating ? 'fill-primary text-primary' : 'text-muted-foreground/30'}`}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Default reviews list with an aggregate header — token-only so it inherits the\n * host theme. Optional: a host with bespoke review cards can ignore this and map\n * `useReviews()` / `useReviewSummary()` itself (as hempdent does on its home).\n */\nexport function ReviewsList({ limit, heading }: { limit?: number; heading?: string }) {\n const { reviews, loading } = useReviews({ limit })\n const { summary } = useReviewSummary()\n\n return (\n <section className=\"py-16 bg-background\">\n <div className=\"container mx-auto px-6\">\n <div className=\"text-center mb-12\">\n {heading ? (\n <h1 className=\"font-heading text-4xl md:text-5xl font-bold text-foreground mb-3\">{heading}</h1>\n ) : null}\n {summary ? (\n <div className=\"flex items-center justify-center gap-2\">\n <Stars rating={Math.round(summary.average)} />\n <span className=\"text-foreground font-semibold text-lg\">{summary.average}</span>\n <span className=\"text-muted-foreground text-sm\">· {summary.count} avaliações</span>\n </div>\n ) : null}\n </div>\n\n {loading ? (\n <p className=\"text-center text-muted-foreground\">Carregando avaliações…</p>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {reviews.map((review) => (\n <div key={review.id} className=\"rounded-2xl bg-card border border-border p-6 shadow-sm\">\n <div className=\"mb-3\">\n <Stars rating={review.rating} />\n </div>\n <p className=\"text-foreground text-sm leading-relaxed mb-4\">\"{review.text}\"</p>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"h-8 w-8 rounded-full bg-accent flex items-center justify-center text-primary font-semibold text-sm\">\n {review.author[0]}\n </div>\n <span className=\"text-sm font-medium text-foreground\">{review.author}</span>\n </div>\n <span className=\"text-xs text-muted-foreground\">{review.date}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </section>\n )\n}\n","import { createElement, type FC, type ReactNode } from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { createSafeDataProvider } from '@fayz-ai/core'\nimport { createMockReputationProvider, type ReputationSeed } from '../data/mock'\nimport { createSupabaseReputationProvider } from '../data/supabase'\nimport { ReputationProvider, type ReputationContextValue } from '../context'\nimport { ReviewsList } from '../components/ReviewsList'\nimport type { ReputationDataProvider } from '../data/types'\n\n// ---------------------------------------------------------------------------\n// @fayz-ai/plugin-reputation/public — website reviews surface.\n//\n// Lean entry (no admin ReputationHome / @fayz-ai/ui). Returns a { manifest,\n// Provider } bundle the host reads uniformly: the Provider wraps the app root so\n// useReviews()/useReviewSummary() power the host's own review markup, and\n// manifest.routes ships an optional /reviews page.\n// ---------------------------------------------------------------------------\n\nexport interface ReputationWebsiteOptions {\n /** Base path for the optional public \"all reviews\" page. Default '/reviews'. */\n basePath?: string\n /** Seed reviews + summary for the mock provider (used until a real backend is wired). */\n seed?: ReputationSeed\n /** Inject a custom provider. Overrides the safe mock/Supabase resolver. */\n dataProvider?: ReputationDataProvider\n /** Heading for the optional /reviews screen. */\n heading?: string\n scope?: PluginScope\n verticalId?: VerticalId\n}\n\nexport interface ReputationWebsitePlugin {\n manifest: PluginManifest\n Provider: FC<{ children: ReactNode }>\n dataProvider: ReputationDataProvider\n}\n\nexport function createReputationWebsite(options?: ReputationWebsiteOptions): ReputationWebsitePlugin {\n const basePath = options?.basePath ?? '/reviews'\n const heading = options?.heading ?? 'O que os pacientes dizem'\n const provider =\n options?.dataProvider ??\n createSafeDataProvider(\n () => createSupabaseReputationProvider(),\n () => createMockReputationProvider({ seed: options?.seed }),\n )\n\n const value: ReputationContextValue = { provider }\n const Provider: FC<{ children: ReactNode }> = ({ children }) =>\n createElement(ReputationProvider, { value, children })\n Provider.displayName = 'ReputationWebsiteProvider'\n\n const ReviewsScreen: FC<unknown> = () => createElement(ReviewsList, { heading })\n ReviewsScreen.displayName = 'ReviewsScreen'\n\n const manifest: PluginManifest = {\n id: 'reputation',\n name: 'Reviews',\n icon: 'Star',\n version: '0.1.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n scaffolds: ['website', 'landing_page'],\n defaultEnabled: true,\n dependencies: [],\n navigation: [],\n routes: [{ path: basePath, component: ReviewsScreen, guard: 'public' }],\n widgets: [],\n }\n\n return { manifest, Provider, dataProvider: provider }\n}\n\n// Public API — website surface\nexport type { Review, ReviewSummary, ReviewSource, ReviewListQuery } from '../types'\nexport type { ReputationDataProvider } from '../data/types'\nexport { createMockReputationProvider, createSupabaseReputationProvider } from '../data'\nexport type { ReputationSeed } from '../data/mock'\nexport { ReputationProvider, useReputationContext } from '../context'\nexport type { ReputationContextValue } from '../context'\nexport { useReviews, useReviewSummary } from '../hooks'\nexport { ReviewsList } from '../components/ReviewsList'\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useReviews.ts","../../src/components/ReviewsList.tsx","../../src/hooks/useProductReviews.ts","../../src/components/Stars.tsx","../../src/components/ProductRating.tsx","../../src/components/ProductReviews.tsx","../../src/components/TopReviews.tsx","../../src/public/index.tsx"],"names":["useState","useEffect","jsx","Stars","wrap","jsxs","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useState } from 'react'\nimport { useReputationContext } from '../context'\nimport type { Review, ReviewListQuery } from '../types'\n\nexport interface UseReviewsResult {\n reviews: Review[]\n loading: boolean\n error: Error | null\n}\n\n/** Fetch the review list from the active reputation provider. */\nexport function useReviews(query?: ReviewListQuery): UseReviewsResult {\n const { provider } = useReputationContext()\n const [reviews, setReviews] = useState<Review[]>([])\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const limit = query?.limit\n const minRating = query?.minRating\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider\n .listReviews({ limit, minRating })\n .then((result) => {\n if (!active) return\n setReviews(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider, limit, minRating])\n\n return { reviews, loading, error }\n}\n","import { Star } from 'lucide-react'\nimport { useReviews } from '../hooks/useReviews'\nimport { useReviewSummary } from '../hooks/useReviewSummary'\n\nfunction Stars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5\">\n {[1, 2, 3, 4, 5].map((i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i <= rating ? 'fill-primary text-primary' : 'text-muted-foreground/30'}`}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Default reviews list with an aggregate header — token-only so it inherits the\n * host theme. Optional: a host with bespoke review cards can ignore this and map\n * `useReviews()` / `useReviewSummary()` itself (as hempdent does on its home).\n */\nexport function ReviewsList({ limit, heading }: { limit?: number; heading?: string }) {\n const { reviews, loading } = useReviews({ limit })\n const { summary } = useReviewSummary()\n\n return (\n <section className=\"py-16 bg-background\">\n <div className=\"container mx-auto px-6\">\n <div className=\"text-center mb-12\">\n {heading ? (\n <h1 className=\"font-heading text-4xl md:text-5xl font-bold text-foreground mb-3\">{heading}</h1>\n ) : null}\n {summary ? (\n <div className=\"flex items-center justify-center gap-2\">\n <Stars rating={Math.round(summary.average)} />\n <span className=\"text-foreground font-semibold text-lg\">{summary.average}</span>\n <span className=\"text-muted-foreground text-sm\">· {summary.count} avaliações</span>\n </div>\n ) : null}\n </div>\n\n {loading ? (\n <p className=\"text-center text-muted-foreground\">Carregando avaliações…</p>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {reviews.map((review) => (\n <div key={review.id} className=\"rounded-2xl bg-card border border-border p-6 shadow-sm\">\n <div className=\"mb-3\">\n <Stars rating={review.rating} />\n </div>\n <p className=\"text-foreground text-sm leading-relaxed mb-4\">\"{review.text}\"</p>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"h-8 w-8 rounded-full bg-accent flex items-center justify-center text-primary font-semibold text-sm\">\n {review.author[0]}\n </div>\n <span className=\"text-sm font-medium text-foreground\">{review.author}</span>\n </div>\n <span className=\"text-xs text-muted-foreground\">{review.date}</span>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </section>\n )\n}\n","import { useEffect, useState } from 'react'\nimport { useReputationContext } from '../context'\nimport type { Review, ReviewSummary, ProductReviewQuery, TopReviewsQuery } from '../types'\n\nconst EMPTY_SUMMARY: ReviewSummary = { average: 0, count: 0, distribution: [] }\n\nexport interface UseProductRatingResult {\n rating: ReviewSummary\n loading: boolean\n error: Error | null\n}\n\n/**\n * The aggregate for one product — one row, not a list.\n *\n * `productId` may be undefined while the PDP is still resolving its product;\n * the hook stays idle rather than firing a query for `undefined`.\n */\nexport function useProductRating(productId: string | undefined): UseProductRatingResult {\n const { provider } = useReputationContext()\n const [rating, setRating] = useState<ReviewSummary>(EMPTY_SUMMARY)\n const [loading, setLoading] = useState(Boolean(productId))\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n if (!productId) {\n setRating(EMPTY_SUMMARY)\n setLoading(false)\n return\n }\n let active = true\n setLoading(true)\n provider\n .getProductRating(productId)\n .then((result) => {\n if (!active) return\n setRating(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n setRating(EMPTY_SUMMARY)\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider, productId])\n\n return { rating, loading, error }\n}\n\nexport interface UseProductReviewsResult {\n reviews: Review[]\n loading: boolean\n error: Error | null\n}\n\n/** The review list under a PDP. */\nexport function useProductReviews(query: Partial<ProductReviewQuery>): UseProductReviewsResult {\n const { provider } = useReputationContext()\n const [reviews, setReviews] = useState<Review[]>([])\n const [loading, setLoading] = useState(Boolean(query.productId))\n const [error, setError] = useState<Error | null>(null)\n\n const { productId, limit, minRating, sort } = query\n\n useEffect(() => {\n if (!productId) {\n setReviews([])\n setLoading(false)\n return\n }\n let active = true\n setLoading(true)\n provider\n .listProductReviews({ productId, limit, minRating, sort })\n .then((result) => {\n if (!active) return\n setReviews(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n setReviews([])\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider, productId, limit, minRating, sort])\n\n return { reviews, loading, error }\n}\n\n/** Social proof for a homepage section. */\nexport function useTopReviews(query?: TopReviewsQuery): UseProductReviewsResult {\n const { provider } = useReputationContext()\n const [reviews, setReviews] = useState<Review[]>([])\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const limit = query?.limit\n const minRating = query?.minRating\n const productOnly = query?.productOnly\n // Arrays are a new reference every render; the join is what makes the effect\n // fire on a real change instead of on every parent re-render.\n const productKey = query?.productIds?.join(',') ?? ''\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider\n .listTopReviews({\n limit,\n minRating,\n productOnly,\n productIds: productKey ? productKey.split(',') : undefined,\n })\n .then((result) => {\n if (!active) return\n setReviews(result)\n setError(null)\n })\n .catch((err) => {\n if (!active) return\n setError(err instanceof Error ? err : new Error(String(err)))\n setReviews([])\n })\n .finally(() => {\n if (active) setLoading(false)\n })\n return () => {\n active = false\n }\n }, [provider, limit, minRating, productOnly, productKey])\n\n return { reviews, loading, error }\n}\n","import type { CSSProperties } from 'react'\n\n// ---------------------------------------------------------------------------\n// The star row. Deliberately an inline SVG and not lucide-react: this component\n// renders inside the lean ./public bundle a storefront pulls, and a five-icon\n// row is not worth an icon-library dependency on that path.\n//\n// Half stars are real, via a clip on a second overlaid row — a 4.5 that renders\n// as 5 solid stars is a lie a shopper can check against the number next to it.\n// ---------------------------------------------------------------------------\n\nexport interface StarsProps {\n /** 0–5. Rendered to the nearest half. */\n value: number\n /** Pixel size of one star. Default 16. */\n size?: number\n /** Colour of a filled star. Default a warm amber. */\n color?: string\n /** Colour of the empty remainder. Default a neutral grey. */\n emptyColor?: string\n className?: string\n /** Screen-reader label. Pass null to hide it when an adjacent number says it. */\n label?: string | null\n}\n\nfunction Row({ size, color, count = 5 }: { size: number; color: string; count?: number }) {\n return (\n <>\n {Array.from({ length: count }, (_, i) => (\n <svg key={i} width={size} height={size} viewBox=\"0 0 24 24\" fill={color} aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 17.3l-6.16 3.73 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.48 4.76 1.64 7.03z\" />\n </svg>\n ))}\n </>\n )\n}\n\nexport function Stars({ value, size = 16, color = '#f59e0b', emptyColor = '#d4d4d8', className, label }: StarsProps) {\n const clamped = Math.max(0, Math.min(5, Number.isFinite(value) ? value : 0))\n const rounded = Math.round(clamped * 2) / 2\n const wrap: CSSProperties = { position: 'relative', display: 'inline-flex', lineHeight: 0, flexShrink: 0 }\n const overlay: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'inline-flex',\n lineHeight: 0,\n overflow: 'hidden',\n width: `${(rounded / 5) * 100}%`,\n }\n return (\n <span\n className={className}\n style={wrap}\n role=\"img\"\n aria-label={label === null ? undefined : (label ?? `${rounded} de 5 estrelas`)}\n aria-hidden={label === null ? true : undefined}\n >\n <Row size={size} color={emptyColor} />\n <span style={overlay} aria-hidden=\"true\">\n <Row size={size} color={color} />\n </span>\n </span>\n )\n}\n","import type { CSSProperties } from 'react'\nimport { Stars } from './Stars'\nimport { useProductRating } from '../hooks/useProductReviews'\n\n// ---------------------------------------------------------------------------\n// The compact \"★★★★☆ 4,5 (12)\" line. Two places want it — under a PDP title and\n// on a catalogue card — so it takes its rating either from the provider (pass a\n// productId) or from a value the caller already has (a grid that fetched every\n// rating in one round trip via getProductRatings, rather than N queries).\n// ---------------------------------------------------------------------------\n\nexport interface ProductRatingProps {\n productId?: string\n /** Pre-fetched aggregate. Skips the per-card query. */\n average?: number\n count?: number\n size?: number\n /** Hide the \"(12)\" tail. */\n hideCount?: boolean\n /** What to render when nothing has been reviewed yet. Default: nothing. */\n emptyLabel?: string\n className?: string\n onClick?: () => void\n}\n\nconst wrap: CSSProperties = { display: 'inline-flex', alignItems: 'center', gap: '0.4rem', fontSize: '0.875rem' }\n\nexport function ProductRating({\n productId,\n average,\n count,\n size = 15,\n hideCount = false,\n emptyLabel,\n className,\n onClick,\n}: ProductRatingProps) {\n // Only queries when the caller did not already supply the numbers.\n const fetched = useProductRating(average == null ? productId : undefined)\n const value = average ?? fetched.rating.average\n const total = count ?? fetched.rating.count\n\n if (total === 0) {\n return emptyLabel ? <span className={className} style={{ ...wrap, opacity: 0.7 }}>{emptyLabel}</span> : null\n }\n\n const label = `${value.toFixed(1).replace('.', ',')} de 5, ${total} ${total === 1 ? 'avaliação' : 'avaliações'}`\n const content = (\n <>\n <Stars value={value} size={size} label={null} />\n <span style={{ fontWeight: 600 }}>{value.toFixed(1).replace('.', ',')}</span>\n {!hideCount && <span style={{ opacity: 0.7 }}>({total})</span>}\n </>\n )\n\n // A rating that scrolls to the reviews is a button, not a div with a handler —\n // otherwise it is unreachable by keyboard.\n return onClick ? (\n <button\n type=\"button\"\n onClick={onClick}\n className={className}\n style={{ ...wrap, background: 'none', border: 0, padding: 0, cursor: 'pointer', font: 'inherit' }}\n aria-label={`${label}. Ver avaliações.`}\n >\n {content}\n </button>\n ) : (\n <span className={className} style={wrap} role=\"img\" aria-label={label}>\n {content}\n </span>\n )\n}\n","import type { CSSProperties } from 'react'\nimport { Stars } from './Stars'\nimport { ProductRating } from './ProductRating'\nimport { useProductRating, useProductReviews } from '../hooks/useProductReviews'\nimport type { Review } from '../types'\n\n// ---------------------------------------------------------------------------\n// The reviews block under a PDP: the aggregate, the star distribution, and the\n// feed. Unstyled beyond layout — colours come from `currentColor` and the host's\n// own background, so it inherits a storefront's theme instead of fighting it.\n// ---------------------------------------------------------------------------\n\nexport interface ProductReviewsProps {\n productId: string\n heading?: string\n /** How many to show. Default 6. */\n limit?: number\n sort?: 'recent' | 'rating'\n /** Rendered when the product has no approved reviews. Default: a quiet line. */\n emptyState?: React.ReactNode\n className?: string\n}\n\nconst card: CSSProperties = { display: 'flex', flexDirection: 'column', gap: '0.5rem' }\n\nfunction DistributionBar({ stars, count, total }: { stars: number; count: number; total: number }) {\n const pct = total === 0 ? 0 : Math.round((count / total) * 100)\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', fontSize: '0.8125rem' }}>\n <span style={{ width: '1.5rem', textAlign: 'right', opacity: 0.7 }}>{stars}★</span>\n <span\n style={{ flex: 1, height: 6, borderRadius: 3, background: 'currentColor', opacity: 0.12, position: 'relative' }}\n aria-hidden=\"true\"\n >\n <span\n style={{ position: 'absolute', inset: 0, width: `${pct}%`, borderRadius: 3, background: '#f59e0b', opacity: 1 }}\n />\n </span>\n <span style={{ width: '2.5rem', opacity: 0.7 }}>{count}</span>\n </div>\n )\n}\n\nfunction ReviewCard({ review }: { review: Review }) {\n return (\n <article style={{ ...card, paddingBlock: '1rem', borderTop: '1px solid currentColor', borderTopColor: 'rgba(128,128,128,0.25)' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', flexWrap: 'wrap' }}>\n <Stars value={review.rating} size={14} label={`${review.rating} de 5`} />\n <strong style={{ fontSize: '0.9375rem' }}>{review.author}</strong>\n {review.verified && (\n <span\n style={{ fontSize: '0.6875rem', letterSpacing: '0.04em', textTransform: 'uppercase', padding: '2px 6px', borderRadius: 3, background: 'rgba(16,122,90,0.12)', color: '#0d6a58' }}\n >\n Compra verificada\n </span>\n )}\n {review.date && <span style={{ fontSize: '0.8125rem', opacity: 0.6 }}>{review.date}</span>}\n </div>\n {review.title && <h4 style={{ margin: 0, fontSize: '1rem' }}>{review.title}</h4>}\n {review.text && <p style={{ margin: 0, lineHeight: 1.6 }}>{review.text}</p>}\n {review.replyText && (\n <p style={{ margin: '0.25rem 0 0', paddingLeft: '0.85rem', borderLeft: '2px solid rgba(128,128,128,0.35)', opacity: 0.85, lineHeight: 1.6 }}>\n <strong style={{ display: 'block', fontSize: '0.8125rem' }}>Resposta da loja</strong>\n {review.replyText}\n </p>\n )}\n </article>\n )\n}\n\nexport function ProductReviews({\n productId,\n heading = 'Avaliações',\n limit = 6,\n sort = 'recent',\n emptyState,\n className,\n}: ProductReviewsProps) {\n const { rating } = useProductRating(productId)\n const { reviews, loading } = useProductReviews({ productId, limit, sort })\n\n // Nothing at all until the first load resolves: a heading that appears and\n // then empties is worse than one that arrives once, correct.\n if (loading && reviews.length === 0) return null\n\n if (rating.count === 0) {\n return emptyState === undefined ? null : (\n <section className={className} id=\"avaliacoes\">\n <h3 style={{ marginTop: 0 }}>{heading}</h3>\n {emptyState}\n </section>\n )\n }\n\n const distribution = rating.distribution ?? []\n\n return (\n <section className={className} id=\"avaliacoes\" aria-labelledby=\"avaliacoes-heading\">\n <h3 id=\"avaliacoes-heading\" style={{ marginTop: 0 }}>{heading}</h3>\n\n <div style={{ display: 'flex', gap: '2rem', flexWrap: 'wrap', alignItems: 'flex-start', marginBottom: '0.5rem' }}>\n <div style={{ ...card, minWidth: '8rem' }}>\n <span style={{ fontSize: '2.5rem', fontWeight: 650, lineHeight: 1 }}>\n {rating.average.toFixed(1).replace('.', ',')}\n </span>\n <ProductRating average={rating.average} count={rating.count} />\n </div>\n {distribution.length > 0 && (\n <div style={{ flex: '1 1 16rem', minWidth: '12rem', display: 'flex', flexDirection: 'column', gap: '0.3rem' }}>\n {distribution.map((d) => (\n <DistributionBar key={d.stars} stars={d.stars} count={d.count} total={rating.count} />\n ))}\n </div>\n )}\n </div>\n\n {reviews.map((review) => (\n <ReviewCard key={review.id} review={review} />\n ))}\n </section>\n )\n}\n","import type { CSSProperties, ReactNode } from 'react'\nimport { Stars } from './Stars'\nimport { useTopReviews } from '../hooks/useProductReviews'\nimport type { Review, TopReviewsQuery } from '../types'\n\n// ---------------------------------------------------------------------------\n// A homepage social-proof strip, fed by real reviews rather than the storefront's\n// static `testimonials` section.\n//\n// Each card can link to the product it is about, which is the whole reason\n// product_slug is snapshotted onto the review row: the section is a route INTO\n// the catalogue, not just decoration. The host supplies the href shape, because\n// only it knows whether its PDP lives at /product/:slug or /produto/:slug.\n// ---------------------------------------------------------------------------\n\nexport interface TopReviewsProps extends TopReviewsQuery {\n heading?: string\n subheading?: string\n /** Build the PDP link for a review's product. Omit to render unlinked cards. */\n productHref?: (review: Review) => string | undefined\n /** Rendered instead of the section when there is nothing to show. Default: nothing. */\n emptyState?: ReactNode\n className?: string\n}\n\nconst grid: CSSProperties = {\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 16rem), 1fr))',\n gap: '1rem',\n}\n\nconst cardStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.6rem',\n padding: '1.25rem',\n border: '1px solid rgba(128,128,128,0.25)',\n borderRadius: 4,\n height: '100%',\n color: 'inherit',\n textDecoration: 'none',\n}\n\nfunction Card({ review, href }: { review: Review; href?: string }) {\n const body = (\n <>\n <Stars value={review.rating} size={15} label={`${review.rating} de 5`} />\n {review.title && <strong style={{ fontSize: '1rem' }}>{review.title}</strong>}\n {review.text && (\n <p style={{ margin: 0, lineHeight: 1.6, flex: 1 }}>{review.text}</p>\n )}\n <footer style={{ fontSize: '0.8125rem', opacity: 0.75, display: 'flex', gap: '0.4rem', flexWrap: 'wrap' }}>\n <span>{review.author}</span>\n {review.productName && (\n <>\n <span aria-hidden=\"true\">·</span>\n <span>{review.productName}</span>\n </>\n )}\n </footer>\n </>\n )\n return href ? (\n <a href={href} style={cardStyle}>\n {body}\n </a>\n ) : (\n <article style={cardStyle}>{body}</article>\n )\n}\n\nexport function TopReviews({\n heading = 'O que dizem nossos clientes',\n subheading,\n productHref,\n emptyState,\n className,\n ...query\n}: TopReviewsProps) {\n const { reviews, loading } = useTopReviews(query)\n\n if (loading && reviews.length === 0) return null\n if (reviews.length === 0) return emptyState === undefined ? null : <>{emptyState}</>\n\n return (\n <section className={className} aria-labelledby=\"top-reviews-heading\">\n <h2 id=\"top-reviews-heading\" style={{ marginTop: 0 }}>{heading}</h2>\n {subheading && <p style={{ marginTop: '-0.5rem', opacity: 0.75 }}>{subheading}</p>}\n <div style={grid}>\n {reviews.map((review) => (\n <Card key={review.id} review={review} href={productHref?.(review)} />\n ))}\n </div>\n </section>\n )\n}\n","import { createElement, type FC, type ReactNode } from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { createSafeDataProvider } from '@fayz-ai/core'\nimport { createMockReputationProvider, type ReputationSeed } from '../data/mock'\nimport { createSupabaseReputationProvider } from '../data/supabase'\nimport { ReputationProvider, type ReputationContextValue } from '../context'\nimport { ReviewsList } from '../components/ReviewsList'\nimport type { ReputationDataProvider } from '../data/types'\n\n// ---------------------------------------------------------------------------\n// @fayz-ai/plugin-reputation/public — website reviews surface.\n//\n// Lean entry (no admin ReputationHome / @fayz-ai/ui). Returns a { manifest,\n// Provider } bundle the host reads uniformly: the Provider wraps the app root so\n// useReviews()/useReviewSummary() power the host's own review markup, and\n// manifest.routes ships an optional /reviews page.\n// ---------------------------------------------------------------------------\n\nexport interface ReputationWebsiteOptions {\n /** Base path for the optional public \"all reviews\" page. Default '/reviews'. */\n basePath?: string\n /** Seed reviews + summary for the mock provider (used until a real backend is wired). */\n seed?: ReputationSeed\n /** Inject a custom provider. Overrides the safe mock/Supabase resolver. */\n dataProvider?: ReputationDataProvider\n /** Tenant whose approved reviews to read. An anon storefront has no session,\n * so without this the Supabase provider has no tenant and falls back to seed. */\n tenantId?: string\n /** Heading for the optional /reviews screen. */\n heading?: string\n scope?: PluginScope\n verticalId?: VerticalId\n}\n\nexport interface ReputationWebsitePlugin {\n manifest: PluginManifest\n Provider: FC<{ children: ReactNode }>\n dataProvider: ReputationDataProvider\n}\n\nexport function createReputationWebsite(options?: ReputationWebsiteOptions): ReputationWebsitePlugin {\n const basePath = options?.basePath ?? '/reviews'\n const heading = options?.heading ?? 'O que os pacientes dizem'\n const provider =\n options?.dataProvider ??\n createSafeDataProvider(\n () => createSupabaseReputationProvider({ tenantId: options?.tenantId }),\n () => createMockReputationProvider({ seed: options?.seed }),\n )\n\n const value: ReputationContextValue = { provider }\n const Provider: FC<{ children: ReactNode }> = ({ children }) =>\n createElement(ReputationProvider, { value, children })\n Provider.displayName = 'ReputationWebsiteProvider'\n\n const ReviewsScreen: FC<unknown> = () => createElement(ReviewsList, { heading })\n ReviewsScreen.displayName = 'ReviewsScreen'\n\n const manifest: PluginManifest = {\n id: 'reputation',\n name: 'Reviews',\n icon: 'Star',\n version: '0.1.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n scaffolds: ['website', 'landing_page'],\n defaultEnabled: true,\n dependencies: [],\n navigation: [],\n routes: [{ path: basePath, component: ReviewsScreen, guard: 'public' }],\n widgets: [],\n }\n\n return { manifest, Provider, dataProvider: provider }\n}\n\n// Public API — website surface\nexport type {\n Review,\n ReviewSummary,\n ReviewSource,\n ReviewListQuery,\n ReviewStatus,\n ProductReviewQuery,\n TopReviewsQuery,\n} from '../types'\nexport type { ReputationDataProvider } from '../data/types'\nexport { createMockReputationProvider, createSupabaseReputationProvider } from '../data'\nexport type { ReputationSeed } from '../data/mock'\nexport { ReputationProvider, useReputationContext } from '../context'\nexport type { ReputationContextValue } from '../context'\nexport { useReviews, useReviewSummary, useProductRating, useProductReviews, useTopReviews } from '../hooks'\nexport type { UseProductRatingResult, UseProductReviewsResult } from '../hooks'\nexport { ReviewsList } from '../components/ReviewsList'\nexport { Stars } from '../components/Stars'\nexport type { StarsProps } from '../components/Stars'\nexport { ProductRating } from '../components/ProductRating'\nexport type { ProductRatingProps } from '../components/ProductRating'\nexport { ProductReviews } from '../components/ProductReviews'\nexport type { ProductReviewsProps } from '../components/ProductReviews'\nexport { TopReviews } from '../components/TopReviews'\nexport type { TopReviewsProps } from '../components/TopReviews'\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type ReviewSource = 'Google' | 'Facebook' | 'Instagram' | 'Website' | (string & {});
|
|
2
|
+
/** Where a review is in moderation. Only `approved` is ever public. */
|
|
3
|
+
export type ReviewStatus = 'pending' | 'approved' | 'rejected';
|
|
2
4
|
export interface Review {
|
|
3
5
|
id: string;
|
|
4
6
|
/** Reviewer display name. */
|
|
@@ -10,6 +12,24 @@ export interface Review {
|
|
|
10
12
|
source?: ReviewSource;
|
|
11
13
|
/** Whether the business has replied (admin surface). */
|
|
12
14
|
replied?: boolean;
|
|
15
|
+
/** The product this review is about. Absent ⇒ it is about the business. */
|
|
16
|
+
productId?: string;
|
|
17
|
+
/** Display snapshot taken at write time, so a card can render and link
|
|
18
|
+
* without this plugin ever reading plugin-shop's tables. */
|
|
19
|
+
productName?: string;
|
|
20
|
+
productSlug?: string;
|
|
21
|
+
/** Short headline above the body, when the reviewer wrote one. */
|
|
22
|
+
title?: string;
|
|
23
|
+
/** The review is attached to a real order — render the "verified" badge. */
|
|
24
|
+
verified?: boolean;
|
|
25
|
+
/** Reviewer avatar, when one is known. */
|
|
26
|
+
avatarUrl?: string;
|
|
27
|
+
/** The merchant's public reply. */
|
|
28
|
+
replyText?: string;
|
|
29
|
+
/** ISO timestamp — what to sort by. `date` is for display only. */
|
|
30
|
+
publishedAt?: string;
|
|
31
|
+
/** Moderation state. Only present on the backoffice provider. */
|
|
32
|
+
status?: ReviewStatus;
|
|
13
33
|
}
|
|
14
34
|
export interface ReviewSummary {
|
|
15
35
|
/** Average rating, e.g. 4.8. */
|
|
@@ -27,4 +47,41 @@ export interface ReviewListQuery {
|
|
|
27
47
|
/** Minimum rating to include. */
|
|
28
48
|
minRating?: number;
|
|
29
49
|
}
|
|
50
|
+
/** Reviews for one product, newest first unless told otherwise. */
|
|
51
|
+
export interface ProductReviewQuery extends ReviewListQuery {
|
|
52
|
+
productId: string;
|
|
53
|
+
/** `recent` (default) or `rating` — highest rated first. */
|
|
54
|
+
sort?: 'recent' | 'rating';
|
|
55
|
+
}
|
|
56
|
+
/** The homepage "what people say" feed, across every product. */
|
|
57
|
+
export interface TopReviewsQuery extends ReviewListQuery {
|
|
58
|
+
/** Only reviews attached to a product. Default true — a homepage
|
|
59
|
+
* social-proof strip that mixes in business reviews reads as padding. */
|
|
60
|
+
productOnly?: boolean;
|
|
61
|
+
/** Restrict to these products (e.g. the ones already on the page). */
|
|
62
|
+
productIds?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
/** What the backoffice writes. `tenantId` is supplied by the provider. */
|
|
65
|
+
export interface ReviewInput {
|
|
66
|
+
productId?: string | null;
|
|
67
|
+
productName?: string | null;
|
|
68
|
+
productSlug?: string | null;
|
|
69
|
+
orderId?: string | null;
|
|
70
|
+
author: string;
|
|
71
|
+
avatarUrl?: string | null;
|
|
72
|
+
rating: number;
|
|
73
|
+
title?: string | null;
|
|
74
|
+
text?: string;
|
|
75
|
+
source?: ReviewSource;
|
|
76
|
+
status?: ReviewStatus;
|
|
77
|
+
verified?: boolean;
|
|
78
|
+
replyText?: string | null;
|
|
79
|
+
}
|
|
80
|
+
/** Backoffice list query — unlike the public feed, it can see every status. */
|
|
81
|
+
export interface ManagedReviewQuery extends ReviewListQuery {
|
|
82
|
+
status?: ReviewStatus;
|
|
83
|
+
productId?: string;
|
|
84
|
+
/** Only reviews about a product, or only those about the business. */
|
|
85
|
+
kind?: 'product' | 'business';
|
|
86
|
+
}
|
|
30
87
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReputationHome.d.ts","sourceRoot":"","sources":["../../src/views/ReputationHome.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ReputationHome.d.ts","sourceRoot":"","sources":["../../src/views/ReputationHome.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAoCzB,wBAAgB,cAAc,sBA6I7B"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fayz-ai/plugin-reputation",
|
|
3
3
|
"fayz": {
|
|
4
|
-
"status": "preview"
|
|
4
|
+
"status": "preview",
|
|
5
|
+
"dependencies": []
|
|
5
6
|
},
|
|
6
|
-
"version": "0.
|
|
7
|
+
"version": "0.10.1",
|
|
7
8
|
"description": "[experimental] Fayz SDK — reviews & reputation management plugin",
|
|
8
9
|
"type": "module",
|
|
9
10
|
"sideEffects": false,
|
|
@@ -29,8 +30,8 @@
|
|
|
29
30
|
"lucide-react": ">=0.400.0 <1.0.0"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@fayz-ai/core": "^0.
|
|
33
|
-
"@fayz-ai/ui": "^0.
|
|
33
|
+
"@fayz-ai/core": "^0.16.0",
|
|
34
|
+
"@fayz-ai/ui": "^0.16.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/react": "^18.3.0",
|
|
@@ -52,7 +53,8 @@
|
|
|
52
53
|
"scripts": {
|
|
53
54
|
"build": "tsup && tsc -b --force",
|
|
54
55
|
"dev": "tsup --watch",
|
|
55
|
-
"typecheck": "tsc -b",
|
|
56
|
-
"clean": "rm -rf dist .tsbuildinfo"
|
|
56
|
+
"typecheck": "tsc -b tsconfig.test.json",
|
|
57
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
58
|
+
"test": "vitest run"
|
|
57
59
|
}
|
|
58
60
|
}
|