bitsnap-payloadcms 0.0.0-stage → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -2
  3. package/dist/client.d.ts +3 -0
  4. package/dist/client.js +5 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/constants.d.ts +7 -0
  7. package/dist/constants.js +8 -0
  8. package/dist/constants.js.map +1 -0
  9. package/dist/fields/getFields.d.ts +54 -0
  10. package/dist/fields/getFields.js +150 -0
  11. package/dist/fields/getFields.js.map +1 -0
  12. package/dist/fields/index.d.ts +2 -0
  13. package/dist/fields/index.js +3 -0
  14. package/dist/fields/index.js.map +1 -0
  15. package/dist/index.d.ts +7 -0
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/plugin.d.ts +15 -0
  19. package/dist/plugin.js +60 -0
  20. package/dist/plugin.js.map +1 -0
  21. package/dist/server/client.d.ts +47 -0
  22. package/dist/server/client.js +68 -0
  23. package/dist/server/client.js.map +1 -0
  24. package/dist/server/endpoints.d.ts +9 -0
  25. package/dist/server/endpoints.js +190 -0
  26. package/dist/server/endpoints.js.map +1 -0
  27. package/dist/server/errors.d.ts +9 -0
  28. package/dist/server/errors.js +35 -0
  29. package/dist/server/errors.js.map +1 -0
  30. package/dist/server/index.d.ts +6 -0
  31. package/dist/server/index.js +6 -0
  32. package/dist/server/index.js.map +1 -0
  33. package/dist/server/schemas.d.ts +55 -0
  34. package/dist/server/schemas.js +46 -0
  35. package/dist/server/schemas.js.map +1 -0
  36. package/dist/types.d.ts +75 -0
  37. package/dist/types.js +3 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/ui/BitsnapManager.css +159 -0
  40. package/dist/ui/BitsnapManager.d.ts +5 -0
  41. package/dist/ui/BitsnapManager.js +642 -0
  42. package/dist/ui/BitsnapManager.js.map +1 -0
  43. package/dist/ui/LinkToDoc.d.ts +4 -0
  44. package/dist/ui/LinkToDoc.js +48 -0
  45. package/dist/ui/LinkToDoc.js.map +1 -0
  46. package/dist/ui/ProductSelect.css +199 -0
  47. package/dist/ui/ProductSelect.d.ts +5 -0
  48. package/dist/ui/ProductSelect.js +146 -0
  49. package/dist/ui/ProductSelect.js.map +1 -0
  50. package/dist/ui/getBitsnapClientConfig.d.ts +13 -0
  51. package/dist/ui/getBitsnapClientConfig.js +30 -0
  52. package/dist/ui/getBitsnapClientConfig.js.map +1 -0
  53. package/dist/utils/formatCurrency.d.ts +6 -0
  54. package/dist/utils/formatCurrency.js +24 -0
  55. package/dist/utils/formatCurrency.js.map +1 -0
  56. package/package.json +93 -4
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/BitsnapManager.tsx"],"sourcesContent":["'use client'\n\nimport {\n Banner,\n Button,\n CopyToClipboard,\n FieldDescription,\n Pill,\n SelectInput,\n TextInput,\n useForm,\n useFormFields,\n} from '@payloadcms/ui'\nimport type { UIFieldClientProps } from 'payload'\nimport { type ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'\n\nimport type { BitsnapClientConfig } from '../types.js'\nimport { getBitsnapClientConfig } from './getBitsnapClientConfig.js'\n\nimport './BitsnapManager.css'\n\nexport type BitsnapManagerProps = UIFieldClientProps & Partial<BitsnapClientConfig>\n\ntype ManagedStatus = 'DRAFT' | 'UNPUBLISHED' | 'PUBLISHED'\n\ntype ManagedVariant = {\n id: string\n name: string\n priceAmount: number | null\n priceCurrency: string | null\n availableQuantity: number | null\n}\n\ntype ManagedProduct = {\n id: string\n name: string\n status: ManagedStatus\n priceAmount: number | null\n priceCurrency: string | null\n availableQuantity: number | null\n variants: ManagedVariant[]\n revision: number\n}\n\ntype VariantRow = {\n id?: string\n name: string\n price: string\n stock: string\n}\n\ntype Message = {\n tone: 'success' | 'error'\n text: string\n}\n\nconst statusLabels: Record<ManagedStatus, string> = {\n DRAFT: 'Szkic',\n UNPUBLISHED: 'Nieopublikowany',\n PUBLISHED: 'Opublikowany',\n}\n\n/**\n * Matches any field path that ends with `productID` — layout agnostic on purpose,\n * the plugin must not depend on a specific block layout of the consuming app.\n */\nconst productIDPathPattern = /(?:^|\\.)productID$/\n\n/**\n * Extracts the numeric index of a block/array row out of a field path\n * (`layout.2.productID` -> `2`). Paths without an index sort last.\n */\nconst getPathIndex = (path: string): number => {\n const match = /(?:^|\\.)(\\d+)(?:\\.|$)/.exec(path)\n\n if (!match || match[1] === undefined) {\n return Number.MAX_SAFE_INTEGER\n }\n\n return Number(match[1])\n}\n\nconst getProductIDPaths = (fields: Record<string, { value?: unknown }>): string[] =>\n Object.keys(fields)\n .filter((path) => productIDPathPattern.test(path))\n .sort((a, b) => {\n const indexA = getPathIndex(a)\n const indexB = getPathIndex(b)\n\n if (indexA !== indexB) {\n return indexA - indexB\n }\n\n return a.localeCompare(b)\n })\n\nconst groszeToZl = (grosze: number | null): string =>\n grosze === null ? '' : (grosze / 100).toFixed(2).replace('.', ',')\n\nconst parsePrice = (value: string): number | null | undefined => {\n const trimmed = value.trim()\n if (trimmed === '') return undefined\n const normalized = trimmed.replace(/\\s/g, '').replace(',', '.')\n const parsed = Number.parseFloat(normalized)\n if (!Number.isFinite(parsed) || parsed < 0) return null\n return Math.round(parsed * 100)\n}\n\nconst parseQuantity = (value: string): number | null | undefined => {\n const trimmed = value.trim()\n if (trimmed === '') return undefined\n const parsed = Number(trimmed)\n if (!Number.isInteger(parsed) || parsed < 0) return null\n return parsed\n}\n\nexport const BitsnapManager = (props: BitsnapManagerProps) => {\n const { dispatchFields } = useForm()\n const { apiBaseUrl, currency, dashboardUrl } = getBitsnapClientConfig(props)\n\n const description =\n typeof props.field.admin?.description === 'string' ? props.field.admin.description : undefined\n\n const productIDPathsKey = useFormFields(([fields]) => getProductIDPaths(fields).join(','))\n\n const productIDPaths = useMemo(\n () => (productIDPathsKey === '' ? [] : productIDPathsKey.split(',')),\n [productIDPathsKey],\n )\n\n const linkedProductID = useFormFields(([fields]) => {\n for (const path of getProductIDPaths(fields)) {\n const value = fields[path]?.value\n if (typeof value === 'string' && value !== '') return value\n }\n return null\n })\n\n const productTitle = useFormFields(([fields]) => {\n const value = fields.title?.value\n return typeof value === 'string' ? value : ''\n })\n\n const [status, setStatus] = useState<ManagedStatus>('DRAFT')\n const [price, setPrice] = useState('')\n const [stock, setStock] = useState('')\n const [variants, setVariants] = useState<VariantRow[]>([])\n const [revision, setRevision] = useState<number | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [isSaving, setIsSaving] = useState(false)\n const [message, setMessage] = useState<Message | null>(null)\n\n const [newName, setNewName] = useState<string | null>(null)\n const [newPrice, setNewPrice] = useState('')\n const [newStatus, setNewStatus] = useState<ManagedStatus>('DRAFT')\n const [isCreating, setIsCreating] = useState(false)\n const [createdProductID, setCreatedProductID] = useState<string | null>(null)\n\n const applyProduct = useCallback((product: ManagedProduct) => {\n setStatus(product.status)\n setPrice(groszeToZl(product.priceAmount))\n setStock(product.availableQuantity === null ? '' : String(product.availableQuantity))\n setRevision(product.revision)\n setVariants(\n product.variants.map((variant) => ({\n id: variant.id,\n name: variant.name,\n price: groszeToZl(variant.priceAmount),\n stock: variant.availableQuantity === null ? '' : String(variant.availableQuantity),\n })),\n )\n }, [])\n\n const load = useCallback(async (): Promise<boolean> => {\n if (!linkedProductID) {\n setRevision(null)\n setVariants([])\n return false\n }\n\n setIsLoading(true)\n setMessage(null)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/products/${encodeURIComponent(linkedProductID)}`,\n )\n const payload = (await response.json()) as { product?: ManagedProduct; error?: string }\n\n if (!response.ok || !payload.product) {\n throw new Error(payload.error ?? 'Nie udało się pobrać produktu z Bitsnapa')\n }\n\n applyProduct(payload.product)\n return true\n } catch (error) {\n setMessage({\n tone: 'error',\n text: error instanceof Error ? error.message : 'Nie udało się pobrać produktu z Bitsnapa',\n })\n return false\n } finally {\n setIsLoading(false)\n }\n }, [apiBaseUrl, applyProduct, linkedProductID])\n\n useEffect(() => {\n void load()\n }, [load])\n\n const save = useCallback(async () => {\n if (!linkedProductID || revision === null) return\n\n const priceAmount = parsePrice(price)\n const availableQuantity = parseQuantity(stock)\n\n if (priceAmount === null) {\n setMessage({ tone: 'error', text: 'Cena bazowa musi być liczbą' })\n return\n }\n\n if (availableQuantity === null) {\n setMessage({ tone: 'error', text: 'Limit sztuk musi być liczbą' })\n return\n }\n\n const payloadVariants: {\n id?: string\n name: string\n priceAmount: number\n priceCurrency: string\n availableQuantity?: number\n }[] = []\n\n for (const variant of variants) {\n const name = variant.name.trim()\n const variantPrice = parsePrice(variant.price)\n const variantStock = parseQuantity(variant.stock)\n\n if (name === '') {\n setMessage({ tone: 'error', text: 'Nazwa wariantu jest wymagana' })\n return\n }\n\n if (variantPrice === null || variantPrice === undefined) {\n setMessage({ tone: 'error', text: `Cena wariantu „${name}” jest wymagana` })\n return\n }\n\n if (variantStock === null) {\n setMessage({ tone: 'error', text: `Limit sztuk wariantu „${name}” musi być liczbą` })\n return\n }\n\n payloadVariants.push({\n ...(variant.id ? { id: variant.id } : {}),\n name,\n priceAmount: variantPrice,\n priceCurrency: currency,\n ...(variantStock === undefined ? {} : { availableQuantity: variantStock }),\n })\n }\n\n setIsSaving(true)\n setMessage(null)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/products/${encodeURIComponent(linkedProductID)}`,\n {\n body: JSON.stringify({\n revision,\n status,\n ...(priceAmount === undefined ? {} : { priceAmount }),\n ...(availableQuantity === undefined ? {} : { availableQuantity }),\n variants: payloadVariants,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'PATCH',\n },\n )\n\n const payload = (await response.json()) as { error?: string }\n\n if (!response.ok) {\n if (response.status === 409) {\n setMessage({ tone: 'error', text: 'Produkt zmienił się w Bitsnap — kliknij Odśwież' })\n return\n }\n\n throw new Error(payload.error ?? 'Nie udało się zapisać produktu w Bitsnapie')\n }\n\n const reloaded = await load()\n\n if (reloaded) {\n setMessage({ tone: 'success', text: 'Zapisano w Bitsnapie' })\n }\n } catch (error) {\n setMessage({\n tone: 'error',\n text: error instanceof Error ? error.message : 'Nie udało się zapisać produktu w Bitsnapie',\n })\n } finally {\n setIsSaving(false)\n }\n }, [apiBaseUrl, currency, linkedProductID, load, price, revision, status, stock, variants])\n\n const create = useCallback(async () => {\n const name = (newName ?? productTitle).trim()\n const priceAmount = parsePrice(newPrice)\n\n if (name === '') {\n setMessage({ tone: 'error', text: 'Podaj nazwę produktu' })\n return\n }\n\n if (priceAmount === null || priceAmount === undefined) {\n setMessage({ tone: 'error', text: 'Podaj cenę produktu w zł' })\n return\n }\n\n setIsCreating(true)\n setMessage(null)\n\n try {\n const response = await fetch(`${apiBaseUrl}/products`, {\n body: JSON.stringify({\n name,\n priceAmount,\n priceCurrency: currency,\n status: newStatus,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n\n const payload = (await response.json()) as { id?: string; error?: string }\n\n if (!response.ok || !payload.id) {\n throw new Error(payload.error ?? 'Nie udało się utworzyć produktu w Bitsnapie')\n }\n\n setCreatedProductID(payload.id)\n\n const targetPath = productIDPaths[0]\n\n if (targetPath) {\n dispatchFields({ path: targetPath, type: 'UPDATE', value: payload.id })\n setMessage({\n tone: 'success',\n text: `Utworzono produkt ${payload.id} i przypisano go do bloku produktu`,\n })\n } else {\n setMessage({\n tone: 'success',\n text: `Utworzono produkt ${payload.id}. Dodaj blok produktu i wybierz ten produkt.`,\n })\n }\n } catch (error) {\n setMessage({\n tone: 'error',\n text:\n error instanceof Error ? error.message : 'Nie udało się utworzyć produktu w Bitsnapie',\n })\n } finally {\n setIsCreating(false)\n }\n }, [apiBaseUrl, currency, dispatchFields, newName, newPrice, newStatus, productIDPaths, productTitle])\n\n const updateVariant = (index: number, patch: Partial<VariantRow>) => {\n setVariants((current) =>\n current.map((variant, variantIndex) =>\n variantIndex === index ? { ...variant, ...patch } : variant,\n ),\n )\n }\n\n const statusOptions = (Object.keys(statusLabels) as ManagedStatus[]).map((option) => ({\n label: statusLabels[option],\n value: option,\n }))\n\n const renderStatusSelect = (\n value: ManagedStatus,\n onChange: (value: ManagedStatus) => void,\n path: string,\n ) => (\n <SelectInput\n isClearable={false}\n label=\"Status\"\n name={path}\n onChange={(option) => {\n const next = Array.isArray(option) ? undefined : option?.value\n if (next === 'DRAFT' || next === 'UNPUBLISHED' || next === 'PUBLISHED') {\n onChange(next)\n }\n }}\n options={statusOptions}\n path={path}\n value={value}\n />\n )\n\n const header = (\n <div className=\"group-field__header\">\n <header>\n <h3 className=\"group-field__title\">\n {typeof props.field.label === 'string' ? props.field.label : 'Bitsnap'}\n </h3>\n <FieldDescription path={props.path} description={description} />\n </header>\n </div>\n )\n\n const banner = message && (\n <Banner type={message.tone === 'error' ? 'error' : 'success'}>{message.text}</Banner>\n )\n\n if (!linkedProductID) {\n return (\n <div className=\"group-field group-field--top-level bitsnap-manager\">\n {header}\n <p className=\"bitsnap-manager__lead\">\n Ten produkt nie jest jeszcze powiązany z Bitsnapem. Utwórz go tutaj — id trafi do bloku\n produktu.\n </p>\n {banner}\n <div className=\"field-type row\">\n <div className=\"row__fields\">\n <div className=\"bitsnap-manager__col--half\">\n <TextInput\n label=\"Nazwa\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => setNewName(event.target.value)}\n path=\"bitsnapManager.newName\"\n value={newName ?? productTitle}\n />\n </div>\n <div className=\"bitsnap-manager__col--quarter\">\n <TextInput\n label=\"Cena (zł)\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => setNewPrice(event.target.value)}\n path=\"bitsnapManager.newPrice\"\n placeholder=\"49,00\"\n value={newPrice}\n />\n </div>\n <div className=\"bitsnap-manager__col--quarter\">\n {renderStatusSelect(newStatus, setNewStatus, 'bitsnapManager.newStatus')}\n </div>\n </div>\n </div>\n\n {createdProductID && productIDPaths.length === 0 && (\n <Banner type=\"info\">\n Dodaj blok produktu (np. Zdjęcie produktu) i wybierz w nim produkt {createdProductID}.\n </Banner>\n )}\n\n <div className=\"bitsnap-manager__actions\">\n <Button\n buttonStyle=\"primary\"\n disabled={isCreating}\n onClick={() => {\n void create()\n }}\n >\n {isCreating ? 'Tworzenie…' : 'Utwórz produkt w Bitsnap'}\n </Button>\n </div>\n </div>\n )\n }\n\n const isInitialLoad = isLoading && revision === null\n\n return (\n <div className=\"group-field group-field--top-level bitsnap-manager\">\n {header}\n {banner}\n\n {isInitialLoad ? (\n <div className=\"bitsnap-manager__loading\">\n <div className=\"bitsnap-manager__loading-row\" />\n <div className=\"bitsnap-manager__loading-row\" />\n </div>\n ) : (\n <>\n <div className=\"field-type row\">\n <div className=\"row__fields\">\n <div className=\"bitsnap-manager__col--third\">\n {renderStatusSelect(status, setStatus, 'bitsnapManager.status')}\n </div>\n <div className=\"bitsnap-manager__col--third\">\n <TextInput\n label=\"Cena bazowa (zł)\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => setPrice(event.target.value)}\n path=\"bitsnapManager.price\"\n placeholder=\"49,00\"\n value={price}\n />\n </div>\n <div className=\"bitsnap-manager__col--third\">\n <TextInput\n description=\"Sprzedane i zarezerwowane sztuki są od niego odejmowane. Puste pole — bez zmian.\"\n label=\"Limit sztuk (łącznie)\"\n onChange={(event: ChangeEvent<HTMLInputElement>) => setStock(event.target.value)}\n path=\"bitsnapManager.stock\"\n placeholder=\"np. 100\"\n value={stock}\n />\n </div>\n </div>\n </div>\n\n <section aria-labelledby=\"bitsnap-variants-title\" className=\"bitsnap-manager__variants\">\n <div className=\"bitsnap-manager__variants-header\">\n <h4 className=\"bitsnap-manager__variants-title\" id=\"bitsnap-variants-title\">\n Warianty\n </h4>\n <Pill size=\"small\">{variants.length}</Pill>\n </div>\n\n {variants.length === 0 ? (\n <p className=\"bitsnap-manager__empty\">\n Brak wariantów — produkt sprzedaje się w jednej wersji.\n </p>\n ) : (\n <div className=\"bitsnap-manager__grid\" role=\"table\" aria-label=\"Warianty\">\n <div className=\"bitsnap-manager__grid-head\" role=\"row\">\n <span className=\"field-label\" role=\"columnheader\">\n Nazwa\n </span>\n <span className=\"field-label\" role=\"columnheader\">\n Cena (zł)\n </span>\n <span className=\"field-label\" role=\"columnheader\">\n Limit sztuk\n </span>\n <span role=\"columnheader\" className=\"bitsnap-manager__sr-only\">\n Akcje\n </span>\n </div>\n {variants.map((variant, index) => (\n <div\n className=\"bitsnap-manager__grid-row\"\n key={variant.id ?? `new-${index}`}\n role=\"row\"\n >\n <div role=\"cell\">\n <TextInput\n onChange={(event: ChangeEvent<HTMLInputElement>) =>\n updateVariant(index, { name: event.target.value })\n }\n path={`bitsnapManager.variants.${index}.name`}\n placeholder={`Wariant ${index + 1}, np. M`}\n value={variant.name}\n />\n </div>\n <div role=\"cell\">\n <TextInput\n onChange={(event: ChangeEvent<HTMLInputElement>) =>\n updateVariant(index, { price: event.target.value })\n }\n path={`bitsnapManager.variants.${index}.price`}\n placeholder=\"49,00\"\n value={variant.price}\n />\n </div>\n <div role=\"cell\">\n <TextInput\n onChange={(event: ChangeEvent<HTMLInputElement>) =>\n updateVariant(index, { stock: event.target.value })\n }\n path={`bitsnapManager.variants.${index}.stock`}\n placeholder=\"np. 10\"\n value={variant.stock}\n />\n </div>\n <div role=\"cell\" className=\"bitsnap-manager__remove\">\n <Button\n aria-label={`Usuń wariant ${variant.name || index + 1}`}\n buttonStyle=\"icon-label\"\n icon=\"x\"\n onClick={() =>\n setVariants((current) => current.filter((_, i) => i !== index))\n }\n round\n tooltip=\"Usuń wariant\"\n />\n </div>\n </div>\n ))}\n </div>\n )}\n\n <Button\n buttonStyle=\"icon-label\"\n icon=\"plus\"\n iconPosition=\"left\"\n iconStyle=\"with-border\"\n onClick={() =>\n setVariants((current) => [...current, { name: '', price: '', stock: '' }])\n }\n >\n Dodaj wariant\n </Button>\n </section>\n </>\n )}\n\n <div className=\"bitsnap-manager__actions\">\n <Button\n buttonStyle=\"primary\"\n disabled={isSaving || isLoading || revision === null}\n onClick={() => {\n void save()\n }}\n >\n {isSaving ? 'Zapisywanie…' : 'Zapisz w Bitsnap'}\n </Button>\n <Button\n buttonStyle=\"secondary\"\n disabled={isLoading || isSaving}\n onClick={() => {\n void load()\n }}\n >\n {isLoading && !isInitialLoad ? 'Odświeżanie…' : 'Odśwież'}\n </Button>\n <Button\n buttonStyle=\"subtle\"\n className=\"bitsnap-manager__open\"\n el=\"anchor\"\n newTab\n url={`${dashboardUrl}/app/product/${encodeURIComponent(linkedProductID)}`}\n >\n Otwórz w Bitsnap\n </Button>\n </div>\n\n <div className=\"bitsnap-manager__meta\">\n <span>Produkt w Bitsnap</span>\n <code>{linkedProductID}</code>\n <CopyToClipboard value={linkedProductID} />\n </div>\n </div>\n )\n}\n"],"names":["Banner","Button","CopyToClipboard","FieldDescription","Pill","SelectInput","TextInput","useForm","useFormFields","useCallback","useEffect","useMemo","useState","getBitsnapClientConfig","statusLabels","DRAFT","UNPUBLISHED","PUBLISHED","productIDPathPattern","getPathIndex","path","match","exec","undefined","Number","MAX_SAFE_INTEGER","getProductIDPaths","fields","Object","keys","filter","test","sort","a","b","indexA","indexB","localeCompare","groszeToZl","grosze","toFixed","replace","parsePrice","value","trimmed","trim","normalized","parsed","parseFloat","isFinite","Math","round","parseQuantity","isInteger","BitsnapManager","props","dispatchFields","apiBaseUrl","currency","dashboardUrl","description","field","admin","productIDPathsKey","join","productIDPaths","split","linkedProductID","productTitle","title","status","setStatus","price","setPrice","stock","setStock","variants","setVariants","revision","setRevision","isLoading","setIsLoading","isSaving","setIsSaving","message","setMessage","newName","setNewName","newPrice","setNewPrice","newStatus","setNewStatus","isCreating","setIsCreating","createdProductID","setCreatedProductID","applyProduct","product","priceAmount","availableQuantity","String","map","variant","id","name","load","response","fetch","encodeURIComponent","payload","json","ok","Error","error","tone","text","save","payloadVariants","variantPrice","variantStock","push","priceCurrency","body","JSON","stringify","headers","method","reloaded","create","targetPath","type","updateVariant","index","patch","current","variantIndex","statusOptions","option","label","renderStatusSelect","onChange","isClearable","next","Array","isArray","options","header","div","className","h3","banner","p","event","target","placeholder","length","buttonStyle","disabled","onClick","isInitialLoad","section","aria-labelledby","h4","size","role","aria-label","span","icon","_","i","tooltip","iconPosition","iconStyle","el","newTab","url","code"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { UIFieldClientProps } from 'payload';
2
+ import type { BitsnapClientConfig } from '../types.js';
3
+ export type LinkToDocProps = UIFieldClientProps & Partial<BitsnapClientConfig>;
4
+ export declare const LinkToDoc: (props: LinkToDocProps) => import("react").JSX.Element | null;
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { CopyToClipboard, useFormFields } from '@payloadcms/ui';
4
+ import { getBitsnapClientConfig } from './getBitsnapClientConfig.js';
5
+ export const LinkToDoc = (props)=>{
6
+ const { dashboardUrl } = getBitsnapClientConfig(props);
7
+ const custom = props.field.admin?.custom;
8
+ const nameOfIDField = typeof custom?.nameOfIDField === 'string' ? custom.nameOfIDField : 'bitsnapID';
9
+ const field = useFormFields(([fields])=>fields && fields?.[nameOfIDField] || null);
10
+ const bitsnapID = field?.value;
11
+ const href = `${dashboardUrl}/app`;
12
+ if (bitsnapID) {
13
+ return /*#__PURE__*/ _jsxs("div", {
14
+ children: [
15
+ /*#__PURE__*/ _jsxs("div", {
16
+ children: [
17
+ /*#__PURE__*/ _jsx("span", {
18
+ className: "label",
19
+ style: {
20
+ color: 'var(--theme-elevation-500, #9A9A9A)'
21
+ },
22
+ children: "Zobacz w Bitsnapie"
23
+ }),
24
+ /*#__PURE__*/ _jsx(CopyToClipboard, {
25
+ value: href
26
+ })
27
+ ]
28
+ }),
29
+ /*#__PURE__*/ _jsx("div", {
30
+ style: {
31
+ fontWeight: '600',
32
+ overflow: 'hidden',
33
+ textOverflow: 'ellipsis'
34
+ },
35
+ children: /*#__PURE__*/ _jsx("a", {
36
+ href: href,
37
+ rel: "noreferrer noopener",
38
+ target: "_blank",
39
+ children: href
40
+ })
41
+ })
42
+ ]
43
+ });
44
+ }
45
+ return null;
46
+ };
47
+
48
+ //# sourceMappingURL=LinkToDoc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/LinkToDoc.tsx"],"sourcesContent":["'use client'\n\nimport { CopyToClipboard, useFormFields } from '@payloadcms/ui'\nimport type { UIFieldClientProps } from 'payload'\n\nimport type { BitsnapClientConfig } from '../types.js'\nimport { getBitsnapClientConfig } from './getBitsnapClientConfig.js'\n\nexport type LinkToDocProps = UIFieldClientProps & Partial<BitsnapClientConfig>\n\nexport const LinkToDoc = (props: LinkToDocProps) => {\n const { dashboardUrl } = getBitsnapClientConfig(props)\n\n const custom = props.field.admin?.custom\n const nameOfIDField =\n typeof custom?.nameOfIDField === 'string' ? custom.nameOfIDField : 'bitsnapID'\n\n const field = useFormFields(([fields]) => (fields && fields?.[nameOfIDField]) || null)\n const bitsnapID = field?.value\n\n const href = `${dashboardUrl}/app`\n\n if (bitsnapID) {\n return (\n <div>\n <div>\n <span\n className=\"label\"\n style={{\n color: 'var(--theme-elevation-500, #9A9A9A)',\n }}\n >\n Zobacz w Bitsnapie\n </span>\n <CopyToClipboard value={href} />\n </div>\n <div\n style={{\n fontWeight: '600',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n <a href={href} rel=\"noreferrer noopener\" target=\"_blank\">\n {href}\n </a>\n </div>\n </div>\n )\n }\n\n return null\n}\n"],"names":["CopyToClipboard","useFormFields","getBitsnapClientConfig","LinkToDoc","props","dashboardUrl","custom","field","admin","nameOfIDField","fields","bitsnapID","value","href","div","span","className","style","color","fontWeight","overflow","textOverflow","a","rel","target"],"mappings":"AAAA;;AAEA,SAASA,eAAe,EAAEC,aAAa,QAAQ,iBAAgB;AAI/D,SAASC,sBAAsB,QAAQ,8BAA6B;AAIpE,OAAO,MAAMC,YAAY,CAACC;IACxB,MAAM,EAAEC,YAAY,EAAE,GAAGH,uBAAuBE;IAEhD,MAAME,SAASF,MAAMG,KAAK,CAACC,KAAK,EAAEF;IAClC,MAAMG,gBACJ,OAAOH,QAAQG,kBAAkB,WAAWH,OAAOG,aAAa,GAAG;IAErE,MAAMF,QAAQN,cAAc,CAAC,CAACS,OAAO,GAAK,AAACA,UAAUA,QAAQ,CAACD,cAAc,IAAK;IACjF,MAAME,YAAYJ,OAAOK;IAEzB,MAAMC,OAAO,GAAGR,aAAa,IAAI,CAAC;IAElC,IAAIM,WAAW;QACb,qBACE,MAACG;;8BACC,MAACA;;sCACC,KAACC;4BACCC,WAAU;4BACVC,OAAO;gCACLC,OAAO;4BACT;sCACD;;sCAGD,KAAClB;4BAAgBY,OAAOC;;;;8BAE1B,KAACC;oBACCG,OAAO;wBACLE,YAAY;wBACZC,UAAU;wBACVC,cAAc;oBAChB;8BAEA,cAAA,KAACC;wBAAET,MAAMA;wBAAMU,KAAI;wBAAsBC,QAAO;kCAC7CX;;;;;IAKX;IAEA,OAAO;AACT,EAAC"}
@@ -0,0 +1,199 @@
1
+ /* ProductSelect.css — plain CSS, scoped to the Bitsnap package. No Tailwind, no CSS modules. */
2
+
3
+ .product-select {
4
+ margin: 1rem 0;
5
+ }
6
+
7
+ /* Native select — the Payload admin theme does not style native form controls,
8
+ so background, border, radius, padding and the focus ring are set explicitly. */
9
+ .product-select-trigger {
10
+ display: block;
11
+ width: 100%;
12
+ max-width: 500px;
13
+ min-width: 300px;
14
+ height: 40px;
15
+ padding: 0 14px;
16
+ font-family: var(--font-body, inherit);
17
+ font-size: 14px;
18
+ line-height: 1.5;
19
+ background-color: var(--theme-elevation-100, #262626);
20
+ color: var(--theme-text, #fafafa);
21
+ border: 1px solid var(--theme-elevation-200, #525252);
22
+ border-radius: var(--style-radius-s, 0.3rem);
23
+ outline: none;
24
+ cursor: pointer;
25
+ transition:
26
+ border-color 0.2s,
27
+ box-shadow 0.2s;
28
+ }
29
+
30
+ .product-select-trigger:hover {
31
+ border-color: var(--theme-elevation-150, #525252);
32
+ }
33
+
34
+ .product-select-trigger:focus,
35
+ .product-select-trigger:focus-visible {
36
+ border-color: var(--theme-success-500, #22c55e);
37
+ box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
38
+ outline: none;
39
+ }
40
+
41
+ .product-select-trigger:disabled {
42
+ opacity: 0.5;
43
+ cursor: not-allowed;
44
+ }
45
+
46
+ .product-select-trigger option {
47
+ background-color: var(--theme-elevation-50, #1a1a1a);
48
+ color: var(--theme-text, #fafafa);
49
+ }
50
+
51
+ .product-select-trigger option:disabled {
52
+ color: var(--theme-elevation-500, #9ba5b8);
53
+ }
54
+
55
+ /* Loading placeholder */
56
+ .product-select-loading {
57
+ width: 300px;
58
+ max-width: 100%;
59
+ height: 50px;
60
+ border-radius: var(--style-radius-s, 4px);
61
+ background-color: var(--theme-elevation-100, #262626);
62
+ animation: product-select-pulse 1.4s ease-in-out infinite;
63
+ }
64
+
65
+ @keyframes product-select-pulse {
66
+ 0%,
67
+ 100% {
68
+ opacity: 1;
69
+ }
70
+
71
+ 50% {
72
+ opacity: 0.4;
73
+ }
74
+ }
75
+
76
+ /* Product list item (kept for consumers rendering their own product list) */
77
+ .product-select-item {
78
+ position: relative;
79
+ display: flex;
80
+ align-items: center;
81
+ padding: 8px 10px;
82
+ font-size: 14px;
83
+ color: var(--theme-text, #f5f7fa);
84
+ border-radius: 4px;
85
+ user-select: none;
86
+ outline: none;
87
+ cursor: pointer;
88
+ transition: background-color 0.15s ease;
89
+ }
90
+
91
+ .product-select-item-content {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: 8px;
95
+ flex: 1;
96
+ min-width: 0;
97
+ flex-shrink: 1;
98
+ }
99
+
100
+ .product-select-item-content img {
101
+ flex-shrink: 0;
102
+ object-fit: contain;
103
+ }
104
+
105
+ .product-select-item-name {
106
+ overflow: hidden;
107
+ text-overflow: ellipsis;
108
+ white-space: nowrap;
109
+ }
110
+
111
+ .product-select-item-price {
112
+ flex-shrink: 0;
113
+ flex-grow: 0;
114
+ font-weight: 500;
115
+ color: var(--theme-elevation-500, #9ba5b8);
116
+ white-space: nowrap;
117
+ margin-left: auto;
118
+ }
119
+
120
+ .product-select-item[data-selected='true'] .product-select-item-price {
121
+ color: var(--theme-success-500, #22c55e);
122
+ }
123
+
124
+ .product-select-item-status {
125
+ flex-shrink: 0;
126
+ flex-grow: 0;
127
+ margin-left: auto;
128
+ padding: 2px 6px;
129
+ font-size: 11px;
130
+ line-height: 1.4;
131
+ text-transform: uppercase;
132
+ color: var(--theme-elevation-500, #9ba5b8);
133
+ white-space: nowrap;
134
+ border: 1px solid var(--theme-elevation-200, #525252);
135
+ border-radius: 999px;
136
+ }
137
+
138
+ .product-select-item-status + .product-select-item-price {
139
+ margin-left: 8px;
140
+ }
141
+
142
+ .product-select-item:hover,
143
+ .product-select-item:focus {
144
+ background-color: var(--theme-elevation-100, #2a3441);
145
+ color: var(--theme-text, #f5f7fa);
146
+ }
147
+
148
+ .product-select-item[data-selected='true'] {
149
+ background-color: var(--theme-elevation-100, #2a3441);
150
+ color: var(--theme-text, #f5f7fa);
151
+ }
152
+
153
+ .product-select-item[data-disabled='true'] {
154
+ color: var(--theme-elevation-500, #9ba5b8);
155
+ opacity: 0.5;
156
+ pointer-events: none;
157
+ cursor: not-allowed;
158
+ }
159
+
160
+ /* Selected product summary — read-only, shown under the dropdown */
161
+ .product-select-summary {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 10px;
165
+ margin-top: 8px;
166
+ max-width: 500px;
167
+ padding: 8px 10px;
168
+ background-color: var(--theme-elevation-50, #1f1f1f);
169
+ border: 1px solid var(--theme-elevation-150, #3a3a3a);
170
+ border-radius: 4px;
171
+ }
172
+
173
+ .product-select-summary img {
174
+ flex-shrink: 0;
175
+ width: 40px;
176
+ height: 48px;
177
+ object-fit: cover;
178
+ }
179
+
180
+ .product-select-summary-text {
181
+ display: flex;
182
+ flex-direction: column;
183
+ gap: 2px;
184
+ min-width: 0;
185
+ }
186
+
187
+ .product-select-summary-name {
188
+ overflow: hidden;
189
+ color: var(--theme-text, #f5f7fa);
190
+ font-size: 14px;
191
+ text-overflow: ellipsis;
192
+ white-space: nowrap;
193
+ }
194
+
195
+ .product-select-summary-price {
196
+ color: var(--theme-elevation-500, #9ba5b8);
197
+ font-size: 13px;
198
+ font-weight: 500;
199
+ }
@@ -0,0 +1,5 @@
1
+ import type { UIFieldClientProps } from 'payload';
2
+ import type { BitsnapClientConfig } from '../types.js';
3
+ import './ProductSelect.css';
4
+ export type ProductSelectProps = UIFieldClientProps & Partial<BitsnapClientConfig>;
5
+ export declare const ProductSelect: (props: ProductSelectProps) => import("react").JSX.Element;
@@ -0,0 +1,146 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FieldDescription, FieldLabel, useField } from '@payloadcms/ui';
4
+ import { useEffect, useState } from 'react';
5
+ import { formatCurrency } from '../utils/formatCurrency.js';
6
+ import { getBitsnapClientConfig } from './getBitsnapClientConfig.js';
7
+ import './ProductSelect.css';
8
+ export const ProductSelect = (props)=>{
9
+ const { apiBaseUrl, currency, dashboardUrl } = getBitsnapClientConfig(props);
10
+ const { value = '', setValue } = useField({
11
+ path: props.path
12
+ });
13
+ const [isPending, setIsPending] = useState(false);
14
+ const [products, setProducts] = useState([]);
15
+ const orderedProducts = [
16
+ ...products.filter((item)=>item.isPublished !== false),
17
+ ...products.filter((item)=>item.isPublished === false)
18
+ ];
19
+ async function getProductsList() {
20
+ setIsPending(true);
21
+ try {
22
+ const result = await fetch(`${apiBaseUrl}/shop-products`);
23
+ const payload = await result.json();
24
+ if (payload?.data?.success && Array.isArray(payload.data.result)) {
25
+ setProducts(payload.data.result);
26
+ } else {
27
+ setProducts([]);
28
+ }
29
+ } catch (e) {
30
+ console.warn(e);
31
+ } finally{
32
+ setIsPending(false);
33
+ }
34
+ }
35
+ function onChange(event) {
36
+ const nextID = event.target.value;
37
+ if (nextID === '') {
38
+ return;
39
+ }
40
+ const isDraft = products.some((item)=>item.id === nextID && item.isPublished === false);
41
+ if (isDraft) {
42
+ return;
43
+ }
44
+ setValue(nextID, false);
45
+ }
46
+ useEffect(()=>{
47
+ getProductsList().then().catch();
48
+ }, [
49
+ apiBaseUrl
50
+ ]);
51
+ function getProductImage(item) {
52
+ if (item.images && item.images.length > 0) {
53
+ return item.images[0];
54
+ }
55
+ return item.image_url;
56
+ }
57
+ function getProductPrice(item) {
58
+ if (!item.price) {
59
+ return null;
60
+ }
61
+ return formatCurrency(item.price, item.currency || currency);
62
+ }
63
+ const selectedProduct = products.find((item)=>item.id === value);
64
+ const selectedProductPrice = selectedProduct ? getProductPrice(selectedProduct) : null;
65
+ const rawDescription = props.field.admin?.description;
66
+ let description;
67
+ if (typeof rawDescription === 'string') {
68
+ description = rawDescription;
69
+ } else if (rawDescription !== null && typeof rawDescription === 'object') {
70
+ description = Object.fromEntries(Object.entries(rawDescription).filter((entry)=>typeof entry[1] === 'string'));
71
+ }
72
+ const selectID = `product-select${props.path.replace(/[^a-zA-Z0-9_-]/g, '-')}`;
73
+ return /*#__PURE__*/ _jsxs("div", {
74
+ className: "product-select",
75
+ children: [
76
+ /*#__PURE__*/ _jsx(FieldLabel, {
77
+ htmlFor: selectID,
78
+ label: props.field.label,
79
+ localized: props.field.localized,
80
+ path: props.path,
81
+ required: props.field.required
82
+ }),
83
+ /*#__PURE__*/ _jsx(FieldDescription, {
84
+ path: props.path,
85
+ description: description
86
+ }),
87
+ isPending && /*#__PURE__*/ _jsx("div", {
88
+ className: "product-select-loading"
89
+ }),
90
+ products.length > 0 && /*#__PURE__*/ _jsxs("select", {
91
+ className: "product-select-trigger",
92
+ id: selectID,
93
+ onChange: onChange,
94
+ value: value ?? '',
95
+ children: [
96
+ /*#__PURE__*/ _jsx("option", {
97
+ value: "",
98
+ children: "Wybierz produkt"
99
+ }),
100
+ orderedProducts.map((item)=>{
101
+ const isDraft = item.isPublished === false;
102
+ const price = getProductPrice(item);
103
+ return /*#__PURE__*/ _jsxs("option", {
104
+ disabled: isDraft,
105
+ value: item.id,
106
+ children: [
107
+ isDraft ? `${item.name} — Szkic` : item.name,
108
+ price ? ` — ${price}` : ''
109
+ ]
110
+ }, item.id);
111
+ })
112
+ ]
113
+ }),
114
+ selectedProduct && /*#__PURE__*/ _jsxs("div", {
115
+ className: "product-select-summary",
116
+ children: [
117
+ /*#__PURE__*/ _jsx("img", {
118
+ src: getProductImage(selectedProduct),
119
+ alt: selectedProduct.name
120
+ }),
121
+ /*#__PURE__*/ _jsxs("div", {
122
+ className: "product-select-summary-text",
123
+ children: [
124
+ /*#__PURE__*/ _jsx("span", {
125
+ className: "product-select-summary-name",
126
+ children: selectedProduct.name
127
+ }),
128
+ selectedProductPrice && /*#__PURE__*/ _jsx("span", {
129
+ className: "product-select-summary-price",
130
+ children: selectedProductPrice
131
+ })
132
+ ]
133
+ })
134
+ ]
135
+ }),
136
+ value != null && value != '' && value.startsWith('prodv2') && /*#__PURE__*/ _jsx("div", {
137
+ children: /*#__PURE__*/ _jsx("a", {
138
+ href: `${dashboardUrl}/app/product/${encodeURIComponent(value)}`,
139
+ children: "Edytuj produkt"
140
+ })
141
+ })
142
+ ]
143
+ });
144
+ };
145
+
146
+ //# sourceMappingURL=ProductSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/ProductSelect.tsx"],"sourcesContent":["'use client'\n\nimport { FieldDescription, FieldLabel, useField } from '@payloadcms/ui'\nimport type { StaticDescription, UIFieldClientProps } from 'payload'\nimport type { BitsnapModels } from 'bitsnap-js/models'\nimport { type ChangeEvent, useEffect, useState } from 'react'\n\nimport type { BitsnapClientConfig } from '../types.js'\nimport { formatCurrency } from '../utils/formatCurrency.js'\nimport { getBitsnapClientConfig } from './getBitsnapClientConfig.js'\n\nimport './ProductSelect.css'\n\nexport type ProductSelectProps = UIFieldClientProps & Partial<BitsnapClientConfig>\n\ntype ShopProductsResponse = {\n data?: {\n success?: boolean\n result?: BitsnapModels.Item[]\n }\n}\n\nexport const ProductSelect = (props: ProductSelectProps) => {\n const { apiBaseUrl, currency, dashboardUrl } = getBitsnapClientConfig(props)\n const { value = '', setValue } = useField<string>({ path: props.path })\n const [isPending, setIsPending] = useState(false)\n const [products, setProducts] = useState<BitsnapModels.Item[]>([])\n\n const orderedProducts = [\n ...products.filter((item) => item.isPublished !== false),\n ...products.filter((item) => item.isPublished === false),\n ]\n\n async function getProductsList() {\n setIsPending(true)\n try {\n const result = await fetch(`${apiBaseUrl}/shop-products`)\n\n const payload = (await result.json()) as ShopProductsResponse\n\n if (payload?.data?.success && Array.isArray(payload.data.result)) {\n setProducts(payload.data.result)\n } else {\n setProducts([])\n }\n } catch (e) {\n console.warn(e)\n } finally {\n setIsPending(false)\n }\n }\n\n function onChange(event: ChangeEvent<HTMLSelectElement>) {\n const nextID = event.target.value\n\n if (nextID === '') {\n return\n }\n\n const isDraft = products.some((item) => item.id === nextID && item.isPublished === false)\n\n if (isDraft) {\n return\n }\n\n setValue(nextID, false)\n }\n\n useEffect(() => {\n getProductsList().then().catch()\n }, [apiBaseUrl])\n\n function getProductImage(item: BitsnapModels.Item): string {\n if (item.images && item.images.length > 0) {\n return item.images[0]\n }\n return item.image_url\n }\n\n function getProductPrice(item: BitsnapModels.Item): string | null {\n if (!item.price) {\n return null\n }\n\n return formatCurrency(item.price, item.currency || currency)\n }\n\n const selectedProduct = products.find((item) => item.id === value)\n const selectedProductPrice = selectedProduct ? getProductPrice(selectedProduct) : null\n\n const rawDescription = props.field.admin?.description\n\n let description: StaticDescription | undefined\n\n if (typeof rawDescription === 'string') {\n description = rawDescription\n } else if (rawDescription !== null && typeof rawDescription === 'object') {\n description = Object.fromEntries(\n Object.entries(rawDescription).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n )\n }\n\n const selectID = `product-select${props.path.replace(/[^a-zA-Z0-9_-]/g, '-')}`\n\n return (\n <div className=\"product-select\">\n <FieldLabel\n htmlFor={selectID}\n label={props.field.label}\n localized={props.field.localized}\n path={props.path}\n required={props.field.required}\n />\n <FieldDescription path={props.path} description={description} />\n\n {isPending && <div className=\"product-select-loading\" />}\n\n {products.length > 0 && (\n <select\n className=\"product-select-trigger\"\n id={selectID}\n onChange={onChange}\n value={value ?? ''}\n >\n <option value=\"\">Wybierz produkt</option>\n {orderedProducts.map((item) => {\n const isDraft = item.isPublished === false\n const price = getProductPrice(item)\n\n return (\n <option disabled={isDraft} key={item.id} value={item.id}>\n {isDraft ? `${item.name} — Szkic` : item.name}\n {price ? ` — ${price}` : ''}\n </option>\n )\n })}\n </select>\n )}\n\n {selectedProduct && (\n <div className=\"product-select-summary\">\n <img src={getProductImage(selectedProduct)} alt={selectedProduct.name} />\n <div className=\"product-select-summary-text\">\n <span className=\"product-select-summary-name\">{selectedProduct.name}</span>\n {selectedProductPrice && (\n <span className=\"product-select-summary-price\">{selectedProductPrice}</span>\n )}\n </div>\n </div>\n )}\n\n {value != null && value != '' && value.startsWith('prodv2') && (\n <div>\n <a href={`${dashboardUrl}/app/product/${encodeURIComponent(value)}`}>Edytuj produkt</a>\n </div>\n )}\n </div>\n )\n}\n"],"names":["FieldDescription","FieldLabel","useField","useEffect","useState","formatCurrency","getBitsnapClientConfig","ProductSelect","props","apiBaseUrl","currency","dashboardUrl","value","setValue","path","isPending","setIsPending","products","setProducts","orderedProducts","filter","item","isPublished","getProductsList","result","fetch","payload","json","data","success","Array","isArray","e","console","warn","onChange","event","nextID","target","isDraft","some","id","then","catch","getProductImage","images","length","image_url","getProductPrice","price","selectedProduct","find","selectedProductPrice","rawDescription","field","admin","description","Object","fromEntries","entries","entry","selectID","replace","div","className","htmlFor","label","localized","required","select","option","map","disabled","name","img","src","alt","span","startsWith","a","href","encodeURIComponent"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { BitsnapClientConfig } from '../types.js';
2
+ /**
3
+ * Default path of the plugin REST endpoints, relative to the Payload API root.
4
+ * The plugin mounts its endpoints on `config.routes.api` (default `/api`).
5
+ */
6
+ export declare const DEFAULT_API_BASE_URL = "/api/bitsnap";
7
+ /**
8
+ * Merges the configuration coming from Payload's `clientProps` with the package defaults.
9
+ *
10
+ * It is deliberately a plain function (no `useConfig()`, no context) so it can be called
11
+ * from anywhere — including outside of a Payload `ConfigProvider`.
12
+ */
13
+ export declare const getBitsnapClientConfig: (props?: Partial<BitsnapClientConfig>) => Required<BitsnapClientConfig>;
@@ -0,0 +1,30 @@
1
+ import { DEFAULT_API_BASE_PATH, DEFAULT_CURRENCY, DEFAULT_DASHBOARD_URL } from '../constants.js';
2
+ /**
3
+ * Default path of the plugin REST endpoints, relative to the Payload API root.
4
+ * The plugin mounts its endpoints on `config.routes.api` (default `/api`).
5
+ */ export const DEFAULT_API_BASE_URL = `/api${DEFAULT_API_BASE_PATH}`;
6
+ const stripTrailingSlashes = (value)=>value.replace(/\/+$/, '');
7
+ const normalizeApiBaseUrl = (value)=>{
8
+ const trimmed = stripTrailingSlashes(value.trim());
9
+ return trimmed === '' ? DEFAULT_API_BASE_URL : trimmed;
10
+ };
11
+ const normalizeDashboardUrl = (value)=>{
12
+ const trimmed = stripTrailingSlashes(value.trim());
13
+ return trimmed === '' ? DEFAULT_DASHBOARD_URL : trimmed;
14
+ };
15
+ /**
16
+ * Merges the configuration coming from Payload's `clientProps` with the package defaults.
17
+ *
18
+ * It is deliberately a plain function (no `useConfig()`, no context) so it can be called
19
+ * from anywhere — including outside of a Payload `ConfigProvider`.
20
+ */ export const getBitsnapClientConfig = (props)=>{
21
+ const incoming = props ?? {};
22
+ return {
23
+ apiBaseUrl: normalizeApiBaseUrl(incoming.apiBaseUrl ?? DEFAULT_API_BASE_URL),
24
+ currency: incoming.currency?.trim() || DEFAULT_CURRENCY,
25
+ dashboardUrl: normalizeDashboardUrl(incoming.dashboardUrl ?? DEFAULT_DASHBOARD_URL),
26
+ projectId: incoming.projectId?.trim() ?? ''
27
+ };
28
+ };
29
+
30
+ //# sourceMappingURL=getBitsnapClientConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/getBitsnapClientConfig.ts"],"sourcesContent":["import { DEFAULT_API_BASE_PATH, DEFAULT_CURRENCY, DEFAULT_DASHBOARD_URL } from '../constants.js'\nimport type { BitsnapClientConfig } from '../types.js'\n\n/**\n * Default path of the plugin REST endpoints, relative to the Payload API root.\n * The plugin mounts its endpoints on `config.routes.api` (default `/api`).\n */\nexport const DEFAULT_API_BASE_URL = `/api${DEFAULT_API_BASE_PATH}`\n\nconst stripTrailingSlashes = (value: string): string => value.replace(/\\/+$/, '')\n\nconst normalizeApiBaseUrl = (value: string): string => {\n const trimmed = stripTrailingSlashes(value.trim())\n return trimmed === '' ? DEFAULT_API_BASE_URL : trimmed\n}\n\nconst normalizeDashboardUrl = (value: string): string => {\n const trimmed = stripTrailingSlashes(value.trim())\n return trimmed === '' ? DEFAULT_DASHBOARD_URL : trimmed\n}\n\n/**\n * Merges the configuration coming from Payload's `clientProps` with the package defaults.\n *\n * It is deliberately a plain function (no `useConfig()`, no context) so it can be called\n * from anywhere — including outside of a Payload `ConfigProvider`.\n */\nexport const getBitsnapClientConfig = (\n props?: Partial<BitsnapClientConfig>,\n): Required<BitsnapClientConfig> => {\n const incoming = props ?? {}\n\n return {\n apiBaseUrl: normalizeApiBaseUrl(incoming.apiBaseUrl ?? DEFAULT_API_BASE_URL),\n currency: incoming.currency?.trim() || DEFAULT_CURRENCY,\n dashboardUrl: normalizeDashboardUrl(incoming.dashboardUrl ?? DEFAULT_DASHBOARD_URL),\n projectId: incoming.projectId?.trim() ?? '',\n }\n}\n"],"names":["DEFAULT_API_BASE_PATH","DEFAULT_CURRENCY","DEFAULT_DASHBOARD_URL","DEFAULT_API_BASE_URL","stripTrailingSlashes","value","replace","normalizeApiBaseUrl","trimmed","trim","normalizeDashboardUrl","getBitsnapClientConfig","props","incoming","apiBaseUrl","currency","dashboardUrl","projectId"],"mappings":"AAAA,SAASA,qBAAqB,EAAEC,gBAAgB,EAAEC,qBAAqB,QAAQ,kBAAiB;AAGhG;;;CAGC,GACD,OAAO,MAAMC,uBAAuB,CAAC,IAAI,EAAEH,uBAAuB,CAAA;AAElE,MAAMI,uBAAuB,CAACC,QAA0BA,MAAMC,OAAO,CAAC,QAAQ;AAE9E,MAAMC,sBAAsB,CAACF;IAC3B,MAAMG,UAAUJ,qBAAqBC,MAAMI,IAAI;IAC/C,OAAOD,YAAY,KAAKL,uBAAuBK;AACjD;AAEA,MAAME,wBAAwB,CAACL;IAC7B,MAAMG,UAAUJ,qBAAqBC,MAAMI,IAAI;IAC/C,OAAOD,YAAY,KAAKN,wBAAwBM;AAClD;AAEA;;;;;CAKC,GACD,OAAO,MAAMG,yBAAyB,CACpCC;IAEA,MAAMC,WAAWD,SAAS,CAAC;IAE3B,OAAO;QACLE,YAAYP,oBAAoBM,SAASC,UAAU,IAAIX;QACvDY,UAAUF,SAASE,QAAQ,EAAEN,UAAUR;QACvCe,cAAcN,sBAAsBG,SAASG,YAAY,IAAId;QAC7De,WAAWJ,SAASI,SAAS,EAAER,UAAU;IAC3C;AACF,EAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Formats a minor-unit amount (grosze/cents) as a currency string.
3
+ *
4
+ * Vendored from the consuming app so the package stays self-contained.
5
+ */
6
+ export declare function formatCurrency(amount: number, currency: string, locale?: string): string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Formats a minor-unit amount (grosze/cents) as a currency string.
3
+ *
4
+ * Vendored from the consuming app so the package stays self-contained.
5
+ */ export function formatCurrency(amount, currency, locale) {
6
+ const resolvedLocale = locale ?? (typeof navigator !== 'undefined' ? navigator.language : 'pl');
7
+ const formatter = new Intl.NumberFormat(resolvedLocale, {
8
+ style: 'currency',
9
+ currency,
10
+ minimumFractionDigits: 2,
11
+ maximumFractionDigits: 2
12
+ });
13
+ const result = formatter.format(amount / 100);
14
+ const regex = new RegExp(`(\\.00)(?=\\D*$)`);
15
+ if (currency.toLowerCase() === 'pln') {
16
+ if (result.includes('zł')) {
17
+ return result;
18
+ }
19
+ return (result.replaceAll('PLN', '').trim() + ' zł').replace(regex, '');
20
+ }
21
+ return result.replace(regex, '');
22
+ }
23
+
24
+ //# sourceMappingURL=formatCurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/formatCurrency.ts"],"sourcesContent":["/**\n * Formats a minor-unit amount (grosze/cents) as a currency string.\n *\n * Vendored from the consuming app so the package stays self-contained.\n */\nexport function formatCurrency(amount: number, currency: string, locale?: string): string {\n const resolvedLocale =\n locale ?? (typeof navigator !== 'undefined' ? navigator.language : 'pl')\n\n const formatter = new Intl.NumberFormat(resolvedLocale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n })\n\n const result = formatter.format(amount / 100)\n\n const regex = new RegExp(`(\\\\.00)(?=\\\\D*$)`)\n\n if (currency.toLowerCase() === 'pln') {\n if (result.includes('zł')) {\n return result\n }\n return (result.replaceAll('PLN', '').trim() + ' zł').replace(regex, '')\n }\n\n return result.replace(regex, '')\n}\n"],"names":["formatCurrency","amount","currency","locale","resolvedLocale","navigator","language","formatter","Intl","NumberFormat","style","minimumFractionDigits","maximumFractionDigits","result","format","regex","RegExp","toLowerCase","includes","replaceAll","trim","replace"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,SAASA,eAAeC,MAAc,EAAEC,QAAgB,EAAEC,MAAe;IAC9E,MAAMC,iBACJD,UAAW,CAAA,OAAOE,cAAc,cAAcA,UAAUC,QAAQ,GAAG,IAAG;IAExE,MAAMC,YAAY,IAAIC,KAAKC,YAAY,CAACL,gBAAgB;QACtDM,OAAO;QACPR;QACAS,uBAAuB;QACvBC,uBAAuB;IACzB;IAEA,MAAMC,SAASN,UAAUO,MAAM,CAACb,SAAS;IAEzC,MAAMc,QAAQ,IAAIC,OAAO,CAAC,gBAAgB,CAAC;IAE3C,IAAId,SAASe,WAAW,OAAO,OAAO;QACpC,IAAIJ,OAAOK,QAAQ,CAAC,OAAO;YACzB,OAAOL;QACT;QACA,OAAO,AAACA,CAAAA,OAAOM,UAAU,CAAC,OAAO,IAAIC,IAAI,KAAK,KAAI,EAAGC,OAAO,CAACN,OAAO;IACtE;IAEA,OAAOF,OAAOQ,OAAO,CAACN,OAAO;AAC/B"}