@clicka1/booking 0.2.4 → 0.2.6
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 +9 -2
- package/dist/{SalonBookingModal-ZIIKN2O2.js → SalonBookingModal-YL7PUL7J.js} +3 -3
- package/dist/{SalonBookingModal-ZIIKN2O2.js.map → SalonBookingModal-YL7PUL7J.js.map} +1 -1
- package/dist/{chunk-HA7DFBYI.js → chunk-ANW2GBPY.js} +16 -10
- package/dist/chunk-ANW2GBPY.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +54 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-HA7DFBYI.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../lib/service-category-inference.ts","../../../lib/salon-service-categories.ts","../../../locales/bg.json","../../../locales/en.json","../../../lib/i18n.ts","../../../lib/i18n-react.tsx"],"names":[],"mappings":"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","file":"chunk-ANW2GBPY.js","sourcesContent":["/** Heuristic + cleanup for service categories (price-list import, admin). */\n\nconst RULES: { category: string; patterns: RegExp[] }[] = [\n {\n category: 'Маникюр',\n patterns: [/маникюр/i, /ноктопласт/i, /гел\\s*лак/i, /нокти/i, /олиг/i, /нокът/i],\n },\n {\n category: 'Педикюр',\n patterns: [/педикюр/i, /крака/i, /стъпал/i],\n },\n {\n category: 'Боядисване',\n patterns: [\n /боядис/i,\n /боя\\b/i,\n /тонир/i,\n /колорист/i,\n /балаяж/i,\n /омбре/i,\n /airtouch/i,\n /корен/i,\n /изрусв/i,\n /изрусяв/i,\n ],\n },\n {\n category: 'Мелиране и кичури',\n patterns: [/мелир/i, /кичур/i, /фоли/i, /highlight/i, /плитк/i],\n },\n {\n category: 'Подстригване',\n patterns: [/подстриг/i, /стрижк/i, /прическ/i, /фризьор/i, /коса\\b/i, /детск/i],\n },\n {\n category: 'Брада и бръснене',\n patterns: [/брад/i, /бръсн/i, /мустак/i, /брада/i],\n },\n {\n category: 'Вежди и мигли',\n patterns: [/вежд/i, /мигл/i, /ламинир/i, /оформ.*вежд/i],\n },\n {\n category: 'Грим',\n patterns: [/грим/i, /макиаж/i, /make\\s*up/i],\n },\n {\n category: 'Козметика',\n patterns: [/почистван/i, /пилинг/i, /маска\\b/i, /хидрат/i, /лице\\b/i, /козмет/i, /фacial/i],\n },\n {\n category: 'Епилация',\n patterns: [/епилац/i, /кола\\s*маска/i, /вакс/i, /лазер/i, /депилац/i],\n },\n {\n category: 'Масаж',\n patterns: [/масаж/i, /терапи/i, /релакс/i],\n },\n {\n category: 'Сватбени и прически',\n patterns: [/сватб/i, /прическа/i, /плитк/i, /кок/i],\n },\n];\n\nexport function inferServiceCategory(serviceName: string, salonCategory?: string): string | undefined {\n const name = serviceName.trim();\n if (!name) return undefined;\n\n for (const rule of RULES) {\n if (rule.patterns.some((p) => p.test(name))) return rule.category;\n }\n\n const salon = (salonCategory ?? '').trim();\n if (salon) return salon;\n\n return undefined;\n}\n\nexport function normalizeCategoryLabel(raw: string): string {\n const t = raw.trim().replace(/\\s+/g, ' ');\n if (!t) return '';\n return t.charAt(0).toUpperCase() + t.slice(1);\n}\n\n/** Carry section headers down the list when only some rows have category. */\nexport function fillMissingCategories(\n items: { name: string; category?: string }[],\n salonCategory?: string,\n): void {\n let last = '';\n for (const item of items) {\n const c = normalizeCategoryLabel(item.category ?? '');\n if (c) {\n last = c;\n item.category = c;\n continue;\n }\n if (last) {\n item.category = last;\n continue;\n }\n const inferred = inferServiceCategory(item.name, salonCategory);\n if (inferred) item.category = inferred;\n }\n}\n","import { normalizeCategoryLabel } from '@/lib/service-category-inference';\n\nexport type ServiceCategoryTab = { id: string | null; label: string };\n\n/** Category saved on the service row in admin (no guessing from service name). */\nexport function resolveServiceCategory(service: { category?: string }): string {\n return normalizeCategoryLabel(service.category ?? '');\n}\n\n/**\n * Price lists often tag only the first row in a section — carry that category down\n * to following services until the next explicit category (same as admin import).\n */\nexport function enrichServiceCategories<T extends { category?: string }>(services: T[]): T[] {\n const out = services.map((s) => ({\n ...s,\n category: resolveServiceCategory(s) || undefined,\n }));\n let last = '';\n for (const item of out) {\n if (item.category) {\n last = item.category;\n } else if (last) {\n item.category = last;\n }\n }\n return out;\n}\n\nexport function buildServiceCategoryTabs(\n services: { category?: string }[],\n): ServiceCategoryTab[] {\n const labels = new Set<string>();\n for (const svc of services) {\n const cat = resolveServiceCategory(svc);\n if (cat) labels.add(cat);\n }\n const sorted = [...labels].sort((a, b) => a.localeCompare(b, 'bg'));\n return [{ id: null, label: 'Всички' }, ...sorted.map((cat) => ({ id: cat, label: cat }))];\n}\n\nexport function serviceMatchesCategory(\n service: { category?: string },\n selectedCategory: string | null,\n): boolean {\n if (!selectedCategory) return true;\n return resolveServiceCategory(service) === selectedCategory;\n}\n","{\n \"booking\": {\n \"modal\": {\n \"ariaLabel\": \"Резервация\",\n \"titleDefault\": \"Резервация\",\n \"titleWithStaff\": \"при {name}\",\n \"closeAria\": \"Затвори\",\n \"confirmClose\": \"Сигурни ли сте, че искате да затворите резервацията?\",\n \"stepService\": \"Услуга\",\n \"stepSpecialist\": \"Специалист\",\n \"stepTime\": \"Час\",\n \"stepDetails\": \"Данни\",\n \"stepAria\": \"Стъпка {n}: {label}\",\n \"selectedServices\": \"Избрани услуги\",\n \"services\": \"Услуги\",\n \"serviceCountOne\": \"{count} услуга\",\n \"serviceCountMany\": \"{count} услуги\",\n \"minSuffix\": \"мин\",\n \"remove\": \"Премахни\",\n \"removeAria\": \"Премахни услуга\",\n \"addMoreServices\": \"Добави още услуги\",\n \"hideList\": \"Скрий списъка · {count} избрани\",\n \"add\": \"Добави\",\n \"addService\": \"Добави услуга\",\n \"noServicesInCategory\": \"Няма услуги в избраната категория.\",\n \"selectSpecialist\": \"Избери специалист\",\n \"availableFor\": \"Налични за\",\n \"serviceUnavailable\": \"Тази услуга не е налична за резервация в момента.\",\n \"selectOtherService\": \"Избери друга услуга\",\n \"dateTime\": \"Дата и час\",\n \"timeWithStaff\": \"Час при {name}\",\n \"date\": \"Дата\",\n \"time\": \"Час\",\n \"selectDateFirst\": \"Първо изберете дата.\",\n \"dayClosed\": \"В този ден салонът е затворен.\",\n \"noSlots\": \"Няма свободни часове за избраните услуги.\",\n \"selectServiceFirst\": \"Първо изберете услуга.\",\n \"contactDetails\": \"Данни за контакт\",\n \"name\": \"Име\",\n \"phone\": \"Телефон\",\n \"email\": \"Имейл\",\n \"notes\": \"Бележки (по желание)\",\n \"smsConsentPre\": \"Съгласявам се да получавам SMS напомняния за резервацията от\",\n \"smsConsentPost\": \"на посочения телефон. Прочетох\",\n \"smsConsentAnd\": \"и\",\n \"terms\": \"Общите условия\",\n \"privacy\": \"Политиката за поверителност\",\n \"smsConsentNote\": \"Без отметка резервацията ви остава валидна, но няма да получите SMS напомняние от салона.\",\n \"totalDuration\": \"Общо: {min} мин\",\n \"totalPrice\": \"Общо: {price}\",\n \"startTime\": \"Старт {start} · Готови около {end}\",\n \"depositRequired\": \"Изисква се депозит от\",\n \"paymentFrom\": \"Плащане от\",\n \"securePayment\": \"Защитено плащане чрез\",\n \"back\": \"Назад\",\n \"continue\": \"Продължи\",\n \"sendRequest\": \"Изпрати заявка\",\n \"payAndBook\": \"Плати и резервирай\",\n \"disclaimerPre\": \"За да завършиш резервацията са нужни име, телефон и имейл — използваме ги само за управление на резервацията, потвърждения и напомняния.\",\n \"disclaimerAccept\": \"С изпращането приемаш\"\n },\n \"success\": {\n \"confirmed\": \"Резервацията е потвърдена\",\n \"waitingAt\": \"Очакваме ви в\",\n \"labelService\": \"Услуга\",\n \"labelWhen\": \"Кога\",\n \"timeFormat\": \"{date}, {time} ч.\",\n \"done\": \"Готово\"\n },\n \"errors\": {\n \"noService\": \"Моля, изберете поне една услуга.\",\n \"noName\": \"Моля, въведете вашето име.\",\n \"noPhone\": \"Моля, въведете телефонен номер.\",\n \"noEmail\": \"Моля, въведете имейл.\",\n \"noDate\": \"Моля, изберете дата.\",\n \"noTime\": \"Моля, изберете час.\",\n \"saveFailed\": \"Резервацията не можа да бъде записана. Моля опитайте отново.\",\n \"httpError\": \"Грешка {status}\",\n \"paymentFailed\": \"Грешка при инициализиране на плащането.\",\n \"generic\": \"Грешка при резервация.\"\n }\n },\n \"adminAuth\": {\n \"loading\": \"Зареждане…\",\n \"signIn\": {\n \"title\": \"Вход\",\n \"subtitle\": \"Въведете имейл и парола за достъп до панела.\",\n \"emailLabel\": \"Имейл\",\n \"emailPlaceholder\": \"ime@example.com\",\n \"passwordLabel\": \"Парола\",\n \"passwordPlaceholder\": \"••••••••\",\n \"showPassword\": \"Покажи паролата\",\n \"hidePassword\": \"Скрий паролата\",\n \"submit\": \"Влез\",\n \"submitting\": \"Влизане…\",\n \"forgot\": \"Забравена парола?\",\n \"errorGeneric\": \"Грешка\",\n \"errorLogin\": \"Грешка при вход\"\n },\n \"forgot\": {\n \"back\": \"← Назад\",\n \"title\": \"Забравена парола\",\n \"subtitle\": \"Въведете имейла на акаунта. Ще изпратим линк за задаване на нова парола.\",\n \"submit\": \"Изпрати линк\",\n \"submitting\": \"Изпращане…\",\n \"sentTitle\": \"Провери пощата си\",\n \"sentBody\": \"Изпратихме линк за задаване на нова парола.\",\n \"backToSignIn\": \"Назад към вход\"\n },\n \"setPassword\": {\n \"invalidLink\": \"Невалиден линк.\",\n \"invalidLinkHint\": \"Поискайте нов от страницата за вход.\",\n \"titleCreate\": \"Задай парола\",\n \"titleReset\": \"Нова парола\",\n \"subtitleCreate\": \"Въведи името си и избери парола за достъп до панела.\",\n \"subtitleReset\": \"Въведи нова парола за твоя панел.\",\n \"nameLabel\": \"Име\",\n \"namePlaceholder\": \"Вашето име\",\n \"emailLabel\": \"Имейл\",\n \"emailPlaceholder\": \"ime@example.com\",\n \"passwordLabel\": \"Парола\",\n \"passwordPlaceholder\": \"Поне 8 символа\",\n \"confirmLabel\": \"Потвърди паролата\",\n \"confirmPlaceholder\": \"Повтори паролата\",\n \"show\": \"Покажи\",\n \"hide\": \"Скрий\",\n \"submitCreate\": \"Създай акаунт →\",\n \"submitReset\": \"Смени паролата →\",\n \"submittingCreate\": \"Създаване…\",\n \"submittingReset\": \"Запазване…\",\n \"mismatch\": \"Паролите не съвпадат.\",\n \"doneCreate\": \"Акаунтът е създаден!\",\n \"doneReset\": \"Паролата е сменена!\",\n \"doneRedirect\": \"Влизаш в панела…\",\n \"haveAccount\": \"Вече имаш акаунт?\",\n \"signInLink\": \"Влез\",\n \"errorGeneric\": \"Грешка\"\n }\n },\n \"common\": {\n \"days\": {\n \"monday\": \"Понеделник\",\n \"tuesday\": \"Вторник\",\n \"wednesday\": \"Сряда\",\n \"thursday\": \"Четвъртък\",\n \"friday\": \"Петък\",\n \"saturday\": \"Събота\",\n \"sunday\": \"Неделя\"\n }\n },\n \"adminDashboard\": {\n \"navigation\": \"Навигация\",\n \"tabs\": {\n \"site\": \"Сайт\",\n \"images\": \"Снимки за сайта\",\n \"specialist\": \"Профил на собственика\",\n \"staff\": \"Екип\",\n \"services\": \"Услуги за резервации\",\n \"offers\": \"Оферти\",\n \"brands\": \"Брандове\",\n \"blog\": \"Блог\",\n \"hours\": \"Работно време\",\n \"bookings\": \"Резервации\",\n \"clients\": \"Клиенти\",\n \"domain\": \"Собствен домейн\",\n \"payments\": \"Плащания\",\n \"integrations\": \"Интеграции\",\n \"marketing\": \"Маркетинг\",\n \"legal\": \"Правни\",\n \"account\": \"Акаунт\"\n },\n \"groups\": {\n \"navigation\": \"Навигация\",\n \"content\": \"Съдържание\",\n \"team\": \"Екип\",\n \"settings\": \"Настройки\",\n \"site\": \"Сайт\",\n \"engine\": \"Резервационен модул\",\n \"publicSite\": \"Публичен сайт\",\n \"delivery\": \"Доставка и домейн\",\n \"account\": \"Акаунт\"\n },\n \"actions\": {\n \"save\": \"Запази\",\n \"copyLink\": \"Копирай линка\",\n \"qrCode\": \"QR код\",\n \"closeMenu\": \"Затвори менюто\"\n },\n \"notices\": {\n \"siteSaved\": \"Информацията е запазена.\",\n \"profileSaved\": \"Профилът е запазен.\",\n \"imagesSaved\": \"Снимките са запазени.\",\n \"imagesUploadNeedsSave\": \"Снимките са качени, но не успяхме да ги запазим. Натисни „Запази\\\".\",\n \"servicesSaved\": \"Услугите са запазени.\",\n \"hoursSaved\": \"Работното време е запазено.\",\n \"linkCopied\": \"Линкът е копиран!\"\n },\n \"siteTab\": {\n \"sections\": {\n \"basics\": \"Контакти\",\n \"address\": \"WWW.\",\n \"addressMobile\": \"Адрес / WWW\",\n \"about\": \"За салона\",\n \"faq\": \"FAQ\",\n \"amenities\": \"Удобства\",\n \"amenitiesMobile\": \"Удобства\"\n },\n \"fields\": {\n \"salonName\": \"Име на салона\",\n \"phone\": \"Телефон\",\n \"email\": \"Имейл\",\n \"city\": \"Град\",\n \"language\": \"Език\",\n \"address\": \"Адрес\",\n \"heroTitle\": \"Заглавие на началната страница\",\n \"heroTitleHint\": \"По избор. Ако оставиш празно, ще се покаже името на салона.\",\n \"heroSubtitle\": \"Подзаглавие / tagline\",\n \"heroSubtitleHint\": \"Кратък текст под заглавието (напр. „Красота, която те кара да се чувстваш у дома\\\").\"\n },\n \"languageOptions\": {\n \"bg\": \"Български\",\n \"en\": \"Английски\"\n },\n \"locationFallback\": \"Локация\",\n \"viewAppleMaps\": \"Виж в Apple Maps\",\n \"socialPlaceholder\": \"salonnaprimer\",\n \"connectedDomain\": \"Свързан домейн\",\n \"manage\": \"Управлявай\",\n \"connectOwnDomain\": \"Свържи собствен домейн\",\n \"connectOwnDomainHint\": \"Въведи домейн, който вече си купил, и го насочи към сайта.\"\n }\n }\n}\n","{\n \"booking\": {\n \"modal\": {\n \"ariaLabel\": \"Booking\",\n \"titleDefault\": \"Book\",\n \"titleWithStaff\": \"with {name}\",\n \"closeAria\": \"Close\",\n \"confirmClose\": \"Are you sure you want to close the booking?\",\n \"stepService\": \"Service\",\n \"stepSpecialist\": \"Specialist\",\n \"stepTime\": \"Time\",\n \"stepDetails\": \"Details\",\n \"stepAria\": \"Step {n}: {label}\",\n \"selectedServices\": \"Selected services\",\n \"services\": \"Services\",\n \"serviceCountOne\": \"{count} service\",\n \"serviceCountMany\": \"{count} services\",\n \"minSuffix\": \"min\",\n \"remove\": \"Remove\",\n \"removeAria\": \"Remove service\",\n \"addMoreServices\": \"Add more services\",\n \"hideList\": \"Hide list · {count} selected\",\n \"add\": \"Add\",\n \"addService\": \"Add service\",\n \"noServicesInCategory\": \"No services in this category.\",\n \"selectSpecialist\": \"Choose a specialist\",\n \"availableFor\": \"Available for\",\n \"serviceUnavailable\": \"This service is not available for booking right now.\",\n \"selectOtherService\": \"Choose a different service\",\n \"dateTime\": \"Date & time\",\n \"timeWithStaff\": \"Time with {name}\",\n \"date\": \"Date\",\n \"time\": \"Time\",\n \"selectDateFirst\": \"Please select a date first.\",\n \"dayClosed\": \"The salon is closed on this day.\",\n \"noSlots\": \"No available slots for the selected services.\",\n \"selectServiceFirst\": \"Please select a service first.\",\n \"contactDetails\": \"Your details\",\n \"name\": \"Name\",\n \"phone\": \"Phone\",\n \"email\": \"Email\",\n \"notes\": \"Notes (optional)\",\n \"smsConsentPre\": \"I agree to receive SMS reminders for this booking from\",\n \"smsConsentPost\": \"to the phone number provided. I have read the\",\n \"smsConsentAnd\": \"and\",\n \"terms\": \"Terms & Conditions\",\n \"privacy\": \"Privacy Policy\",\n \"smsConsentNote\": \"Without this, your booking is still valid — you just won't receive SMS reminders from the salon.\",\n \"totalDuration\": \"Total: {min} min\",\n \"totalPrice\": \"Total: {price}\",\n \"startTime\": \"Starts {start} · Done around {end}\",\n \"depositRequired\": \"Deposit required:\",\n \"paymentFrom\": \"Payment of\",\n \"securePayment\": \"Secure payment via\",\n \"back\": \"Back\",\n \"continue\": \"Continue\",\n \"sendRequest\": \"Request booking\",\n \"payAndBook\": \"Pay & book\",\n \"disclaimerPre\": \"To complete your booking we need your name, phone and email — used only to manage your appointment, send confirmations and reminders.\",\n \"disclaimerAccept\": \"By submitting you accept the\"\n },\n \"success\": {\n \"confirmed\": \"Booking confirmed\",\n \"waitingAt\": \"We'll see you at\",\n \"labelService\": \"Service\",\n \"labelWhen\": \"When\",\n \"timeFormat\": \"{date} at {time}\",\n \"done\": \"Done\"\n },\n \"errors\": {\n \"noService\": \"Please select at least one service.\",\n \"noName\": \"Please enter your name.\",\n \"noPhone\": \"Please enter your phone number.\",\n \"noEmail\": \"Please enter your email.\",\n \"noDate\": \"Please select a date.\",\n \"noTime\": \"Please select a time.\",\n \"saveFailed\": \"Your booking could not be saved. Please try again.\",\n \"httpError\": \"Error {status}\",\n \"paymentFailed\": \"Could not initialise payment. Please try again.\",\n \"generic\": \"Something went wrong. Please try again.\"\n }\n },\n \"adminAuth\": {\n \"loading\": \"Loading…\",\n \"signIn\": {\n \"title\": \"Sign in\",\n \"subtitle\": \"Enter your email and password to access the panel.\",\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"name@example.com\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"••••••••\",\n \"showPassword\": \"Show password\",\n \"hidePassword\": \"Hide password\",\n \"submit\": \"Sign in\",\n \"submitting\": \"Signing in…\",\n \"forgot\": \"Forgot password?\",\n \"errorGeneric\": \"Error\",\n \"errorLogin\": \"Sign-in failed\"\n },\n \"forgot\": {\n \"back\": \"← Back\",\n \"title\": \"Forgot password\",\n \"subtitle\": \"Enter the account email. We will send a link to set a new password.\",\n \"submit\": \"Send link\",\n \"submitting\": \"Sending…\",\n \"sentTitle\": \"Check your inbox\",\n \"sentBody\": \"We sent a link to set a new password.\",\n \"backToSignIn\": \"Back to sign in\"\n },\n \"setPassword\": {\n \"invalidLink\": \"Invalid link.\",\n \"invalidLinkHint\": \"Request a new one from the sign-in page.\",\n \"titleCreate\": \"Set password\",\n \"titleReset\": \"New password\",\n \"subtitleCreate\": \"Enter your name and choose a password to access the panel.\",\n \"subtitleReset\": \"Enter a new password for your panel.\",\n \"nameLabel\": \"Name\",\n \"namePlaceholder\": \"Your name\",\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"name@example.com\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"At least 8 characters\",\n \"confirmLabel\": \"Confirm password\",\n \"confirmPlaceholder\": \"Repeat the password\",\n \"show\": \"Show\",\n \"hide\": \"Hide\",\n \"submitCreate\": \"Create account →\",\n \"submitReset\": \"Change password →\",\n \"submittingCreate\": \"Creating…\",\n \"submittingReset\": \"Saving…\",\n \"mismatch\": \"Passwords do not match.\",\n \"doneCreate\": \"Account created!\",\n \"doneReset\": \"Password changed!\",\n \"doneRedirect\": \"Signing you in…\",\n \"haveAccount\": \"Already have an account?\",\n \"signInLink\": \"Sign in\",\n \"errorGeneric\": \"Error\"\n }\n },\n \"common\": {\n \"days\": {\n \"monday\": \"Monday\",\n \"tuesday\": \"Tuesday\",\n \"wednesday\": \"Wednesday\",\n \"thursday\": \"Thursday\",\n \"friday\": \"Friday\",\n \"saturday\": \"Saturday\",\n \"sunday\": \"Sunday\"\n }\n },\n \"adminDashboard\": {\n \"navigation\": \"Navigation\",\n \"tabs\": {\n \"site\": \"Website\",\n \"images\": \"Site images\",\n \"specialist\": \"Owner profile\",\n \"staff\": \"Team\",\n \"services\": \"Booking services\",\n \"offers\": \"Offers\",\n \"brands\": \"Brands\",\n \"blog\": \"Blog\",\n \"hours\": \"Working hours\",\n \"bookings\": \"Booking\",\n \"clients\": \"Clients\",\n \"domain\": \"Custom domain\",\n \"payments\": \"Payments\",\n \"integrations\": \"Integrations\",\n \"marketing\": \"Marketing\",\n \"legal\": \"Legal\",\n \"account\": \"Account\"\n },\n \"groups\": {\n \"navigation\": \"Navigation\",\n \"content\": \"Content\",\n \"team\": \"Team\",\n \"settings\": \"Settings\",\n \"site\": \"Site\",\n \"engine\": \"Booking engine\",\n \"publicSite\": \"Public site\",\n \"delivery\": \"Delivery\",\n \"account\": \"Account\"\n },\n \"actions\": {\n \"save\": \"Save\",\n \"copyLink\": \"Copy link\",\n \"qrCode\": \"QR code\",\n \"closeMenu\": \"Close menu\"\n },\n \"notices\": {\n \"siteSaved\": \"Information saved.\",\n \"profileSaved\": \"Profile saved.\",\n \"imagesSaved\": \"Images saved.\",\n \"imagesUploadNeedsSave\": \"The images were uploaded, but we could not save them. Press \\\"Save\\\".\",\n \"servicesSaved\": \"Services saved.\",\n \"hoursSaved\": \"Working hours saved.\",\n \"linkCopied\": \"Link copied!\"\n },\n \"siteTab\": {\n \"sections\": {\n \"basics\": \"Contacts\",\n \"address\": \"WWW.\",\n \"addressMobile\": \"Address / WWW\",\n \"about\": \"About\",\n \"faq\": \"FAQ\",\n \"amenities\": \"Amenities\",\n \"amenitiesMobile\": \"Amenities\"\n },\n \"fields\": {\n \"salonName\": \"Salon name\",\n \"phone\": \"Phone\",\n \"email\": \"Email\",\n \"city\": \"City\",\n \"language\": \"Language\",\n \"address\": \"Address\",\n \"heroTitle\": \"Hero title\",\n \"heroTitleHint\": \"Optional. If left blank, the salon name will be shown.\",\n \"heroSubtitle\": \"Hero subtitle / tagline\",\n \"heroSubtitleHint\": \"A short line under the title (e.g. \\\"Beauty that feels like home\\\").\"\n },\n \"languageOptions\": {\n \"bg\": \"Bulgarian\",\n \"en\": \"English\"\n },\n \"locationFallback\": \"Location\",\n \"viewAppleMaps\": \"View in Apple Maps\",\n \"socialPlaceholder\": \"salonexample\",\n \"connectedDomain\": \"Connected domain\",\n \"manage\": \"Manage\",\n \"connectOwnDomain\": \"Connect your own domain\",\n \"connectOwnDomainHint\": \"Enter a domain you already bought and point it to the site.\"\n }\n }\n}\n","import bg from '@/locales/bg.json';\nimport en from '@/locales/en.json';\n\nexport type Locale = 'bg' | 'en';\n\nexport type TFunc = (key: string, vars?: Record<string, string | number>) => string;\n\nconst dict: Record<Locale, typeof bg> = { bg, en: en as typeof bg };\n\nfunction resolve(obj: unknown, keys: string[]): string | undefined {\n let cur: unknown = obj;\n for (const k of keys) {\n if (cur == null || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[k];\n }\n return typeof cur === 'string' ? cur : undefined;\n}\n\nfunction interpolate(str: string, vars: Record<string, string | number>): string {\n return str.replace(/\\{(\\w+)\\}/g, (_, k: string) => String(vars[k] ?? `{${k}}`));\n}\n\nexport function normalizeLocale(value: string | null | undefined): Locale {\n const normalized = String(value ?? '').trim().toLowerCase();\n return normalized === 'en' || normalized.startsWith('en-') ? 'en' : 'bg';\n}\n\nexport function getT(locale: Locale): TFunc {\n const translations = dict[locale] ?? dict.bg;\n return function t(key: string, vars?: Record<string, string | number>): string {\n const parts = key.split('.');\n let value = resolve(translations, parts);\n if (value === undefined) {\n value = resolve(dict.bg, parts) ?? key;\n }\n return vars ? interpolate(value, vars) : value;\n };\n}\n","'use client';\n\nimport { createContext, useContext, type ReactNode } from 'react';\nimport { getT, type Locale, type TFunc } from './i18n';\n\nconst I18nContext = createContext<TFunc>(getT('bg'));\n\nexport function I18nProvider({ locale, children }: { locale: Locale; children: ReactNode }) {\n const t = getT(locale);\n return <I18nContext.Provider value={t}>{children}</I18nContext.Provider>;\n}\n\nexport function useT(): TFunc {\n return useContext(I18nContext);\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -33,9 +33,14 @@ type BookingProviderProps = {
|
|
|
33
33
|
* 2. `<meta name="clicka:engine" content="...">`
|
|
34
34
|
* 3. `process.env.NEXT_PUBLIC_CLICKA_ENGINE`
|
|
35
35
|
* 4. `process.env.NEXT_PUBLIC_CLICKA_API_URL`
|
|
36
|
-
* 5. Default: `https://
|
|
36
|
+
* 5. Default: `https://app.alternine.co`
|
|
37
37
|
*/
|
|
38
38
|
engineUrl?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Public API key used for white-label engine access.
|
|
41
|
+
* If omitted, the provider tries env/meta/global fallbacks.
|
|
42
|
+
*/
|
|
43
|
+
apiKey?: string;
|
|
39
44
|
/**
|
|
40
45
|
* BCP-47 locale. If omitted, the provider derives it from
|
|
41
46
|
* `<html lang>`, then `<body data-lang>`, then `navigator.language`,
|
|
@@ -70,7 +75,7 @@ type BookingProviderProps = {
|
|
|
70
75
|
*/
|
|
71
76
|
honorUrlParams?: boolean;
|
|
72
77
|
};
|
|
73
|
-
declare function BookingProvider({ children, salonSlug, engineUrl, locale, successUrl, cancelUrl, accentGradient, formatPrice, onEvent, basePath, autoTriggers, honorUrlParams, }: BookingProviderProps): React__default.JSX.Element;
|
|
78
|
+
declare function BookingProvider({ children, salonSlug, engineUrl, apiKey, locale, successUrl, cancelUrl, accentGradient, formatPrice, onEvent, basePath, autoTriggers, honorUrlParams, }: BookingProviderProps): React__default.JSX.Element;
|
|
74
79
|
|
|
75
80
|
type BookingButtonProps = React__default.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
76
81
|
/** Pre-select this service id when opening the modal. */
|
|
@@ -162,10 +167,12 @@ type BookingWidgetProps = {
|
|
|
162
167
|
/**
|
|
163
168
|
* Origin of the booking engine API.
|
|
164
169
|
* Set this when the client site is a SEPARATE repo from the engine.
|
|
165
|
-
* Example: 'https://
|
|
170
|
+
* Example: 'https://app.alternine.co'
|
|
166
171
|
* Leave empty (default) when the site runs inside the engine repo.
|
|
167
172
|
*/
|
|
168
173
|
engineUrl?: string;
|
|
174
|
+
/** Optional public API key sent as `X-API-Key` to the engine. */
|
|
175
|
+
apiKey?: string;
|
|
169
176
|
/** CSS gradient string for accent fills. Defaults to a solid gradient from primaryColor. */
|
|
170
177
|
accentGradient?: string;
|
|
171
178
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { normalizeLocale, enrichServiceCategories, buildServiceCategoryTabs, I18nProvider, useT } from './chunk-
|
|
2
|
+
import { normalizeLocale, enrichServiceCategories, buildServiceCategoryTabs, I18nProvider, useT } from './chunk-ANW2GBPY.js';
|
|
3
3
|
import { lazy, forwardRef, useMemo, createContext, useImperativeHandle, Suspense, useContext, useState, useRef, useEffect, useCallback } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -264,6 +264,7 @@ function useBookingFlow({
|
|
|
264
264
|
bookingAdvanceDays,
|
|
265
265
|
bookingServices,
|
|
266
266
|
engineUrl = "",
|
|
267
|
+
apiKey,
|
|
267
268
|
successUrl,
|
|
268
269
|
cancelUrl,
|
|
269
270
|
locale = "bg-BG",
|
|
@@ -272,6 +273,13 @@ function useBookingFlow({
|
|
|
272
273
|
const t = useT();
|
|
273
274
|
const api = engineUrl.replace(/\/$/, "");
|
|
274
275
|
const slugPath = `/api/public/v1/salons/${encodeURIComponent(slug)}`;
|
|
276
|
+
const requestHeaders = useMemo(
|
|
277
|
+
() => ({
|
|
278
|
+
"Content-Type": "application/json",
|
|
279
|
+
...apiKey ? { "X-API-Key": apiKey } : {}
|
|
280
|
+
}),
|
|
281
|
+
[apiKey]
|
|
282
|
+
);
|
|
275
283
|
const [bookingOpen, setBookingOpen] = useState(false);
|
|
276
284
|
const [selectedServiceIdxs, setSelectedServiceIdxs] = useState([]);
|
|
277
285
|
const [selectedDate, setSelectedDate] = useState("");
|
|
@@ -300,18 +308,21 @@ function useBookingFlow({
|
|
|
300
308
|
useEffect(() => {
|
|
301
309
|
if (!bookingOpen || staffFetchedRef.current) return;
|
|
302
310
|
staffFetchedRef.current = true;
|
|
303
|
-
fetch(`${api}${slugPath}/staff`, {
|
|
311
|
+
fetch(`${api}${slugPath}/staff`, {
|
|
312
|
+
cache: "no-store",
|
|
313
|
+
headers: requestHeaders
|
|
314
|
+
}).then((r) => r.json()).then((d) => {
|
|
304
315
|
if (Array.isArray(d.staff)) setStaffMembers(d.staff);
|
|
305
316
|
}).catch(() => {
|
|
306
317
|
});
|
|
307
|
-
}, [bookingOpen,
|
|
318
|
+
}, [api, bookingOpen, requestHeaders, slugPath]);
|
|
308
319
|
useEffect(() => {
|
|
309
320
|
if (!selectedDate) return;
|
|
310
321
|
let cancelled = false;
|
|
311
322
|
const staffParam = selectedStaffMemberId ? `&staffMemberId=${encodeURIComponent(selectedStaffMemberId)}` : "";
|
|
312
323
|
fetch(
|
|
313
324
|
`${api}${slugPath}/slots?date=${encodeURIComponent(selectedDate)}${staffParam}`,
|
|
314
|
-
{ cache: "no-store" }
|
|
325
|
+
{ cache: "no-store", headers: requestHeaders }
|
|
315
326
|
).then((r) => r.json()).then((d) => {
|
|
316
327
|
if (cancelled || !Array.isArray(d.occupied)) return;
|
|
317
328
|
const slots = d.occupied.map((x) => ({
|
|
@@ -325,7 +336,7 @@ function useBookingFlow({
|
|
|
325
336
|
return () => {
|
|
326
337
|
cancelled = true;
|
|
327
338
|
};
|
|
328
|
-
}, [
|
|
339
|
+
}, [api, requestHeaders, selectedDate, selectedStaffMemberId, slugPath]);
|
|
329
340
|
const selectedServices = useMemo(
|
|
330
341
|
() => selectedServiceIdxs.map((i) => bookingServices[i]).filter((s) => Boolean(s)),
|
|
331
342
|
[selectedServiceIdxs, bookingServices]
|
|
@@ -465,7 +476,7 @@ function useBookingFlow({
|
|
|
465
476
|
try {
|
|
466
477
|
const res = await fetch(`${api}${slugPath}/bookings`, {
|
|
467
478
|
method: "POST",
|
|
468
|
-
headers:
|
|
479
|
+
headers: requestHeaders,
|
|
469
480
|
body: JSON.stringify({
|
|
470
481
|
clientName: clientName.trim(),
|
|
471
482
|
clientPhone: clientPhone.trim(),
|
|
@@ -490,7 +501,7 @@ function useBookingFlow({
|
|
|
490
501
|
if (requiresPayment && bookingId) {
|
|
491
502
|
const payRes = await fetch(`${api}${slugPath}/booking-checkout`, {
|
|
492
503
|
method: "POST",
|
|
493
|
-
headers:
|
|
504
|
+
headers: requestHeaders,
|
|
494
505
|
body: JSON.stringify({
|
|
495
506
|
bookingId,
|
|
496
507
|
salonSlug: slug,
|
|
@@ -529,22 +540,26 @@ function useBookingFlow({
|
|
|
529
540
|
setIsSubmitting(false);
|
|
530
541
|
}
|
|
531
542
|
}, [
|
|
532
|
-
|
|
533
|
-
|
|
543
|
+
api,
|
|
544
|
+
cancelUrl,
|
|
545
|
+
clientEmail,
|
|
534
546
|
clientName,
|
|
535
547
|
clientPhone,
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
selectedTime,
|
|
548
|
+
locale,
|
|
549
|
+
markSlotOccupied,
|
|
539
550
|
notes,
|
|
540
|
-
|
|
541
|
-
|
|
551
|
+
onEvent,
|
|
552
|
+
requestHeaders,
|
|
553
|
+
selectedDate,
|
|
554
|
+
selectedServices,
|
|
542
555
|
selectedStaffMemberId,
|
|
543
|
-
|
|
556
|
+
selectedTime,
|
|
557
|
+
slug,
|
|
558
|
+
slugPath,
|
|
544
559
|
successUrl,
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
560
|
+
t,
|
|
561
|
+
totalDuration,
|
|
562
|
+
totalPrice
|
|
548
563
|
]);
|
|
549
564
|
return {
|
|
550
565
|
bookingOpen,
|
|
@@ -581,7 +596,7 @@ function useBookingFlow({
|
|
|
581
596
|
};
|
|
582
597
|
}
|
|
583
598
|
var SalonBookingModal = lazy(
|
|
584
|
-
() => import('./SalonBookingModal-
|
|
599
|
+
() => import('./SalonBookingModal-YL7PUL7J.js').then((m) => ({ default: m.SalonBookingModal }))
|
|
585
600
|
);
|
|
586
601
|
function BookingWidgetInner({
|
|
587
602
|
forwardedRef,
|
|
@@ -594,6 +609,7 @@ function BookingWidgetInner({
|
|
|
594
609
|
serviceCatalog,
|
|
595
610
|
categoryTabs,
|
|
596
611
|
engineUrl,
|
|
612
|
+
apiKey,
|
|
597
613
|
primaryColor,
|
|
598
614
|
accentGradient,
|
|
599
615
|
successUrl,
|
|
@@ -612,6 +628,7 @@ function BookingWidgetInner({
|
|
|
612
628
|
bookingAdvanceDays,
|
|
613
629
|
bookingServices,
|
|
614
630
|
engineUrl,
|
|
631
|
+
apiKey,
|
|
615
632
|
successUrl,
|
|
616
633
|
cancelUrl,
|
|
617
634
|
locale,
|
|
@@ -672,7 +689,7 @@ function BookingWidgetInner({
|
|
|
672
689
|
) });
|
|
673
690
|
}
|
|
674
691
|
var BookingWidget = forwardRef(
|
|
675
|
-
function BookingWidget2({ slug, salon, openingHours: openingHoursProp, bookingBlocks: blocksProp, basePath = "", engineUrl = "", accentGradient, successUrl, cancelUrl, locale: localeProp, formatPrice, onEvent }, ref) {
|
|
692
|
+
function BookingWidget2({ slug, salon, openingHours: openingHoursProp, bookingBlocks: blocksProp, basePath = "", engineUrl = "", apiKey, accentGradient, successUrl, cancelUrl, locale: localeProp, formatPrice, onEvent }, ref) {
|
|
676
693
|
const openingHours = useMemo(
|
|
677
694
|
() => mergeOpeningHours(
|
|
678
695
|
salon.working_hours,
|
|
@@ -749,6 +766,7 @@ var BookingWidget = forwardRef(
|
|
|
749
766
|
serviceCatalog,
|
|
750
767
|
categoryTabs,
|
|
751
768
|
engineUrl,
|
|
769
|
+
apiKey,
|
|
752
770
|
primaryColor,
|
|
753
771
|
accentGradient,
|
|
754
772
|
successUrl,
|
|
@@ -785,10 +803,13 @@ function resolveSlug(prop) {
|
|
|
785
803
|
return prop || readGlobalString("__CLICKA_SALON_SLUG") || readMeta("clicka:salon") || readEnv("NEXT_PUBLIC_SALON_SLUG") || readEnv("NEXT_PUBLIC_CLICKA_SALON");
|
|
786
804
|
}
|
|
787
805
|
function resolveEngine(prop) {
|
|
788
|
-
return prop || readGlobalString("__CLICKA_ENGINE_URL") || readMeta("clicka:engine") || readEnv("NEXT_PUBLIC_ENGINE_URL") || readEnv("NEXT_PUBLIC_CLICKA_ENGINE") || readEnv("NEXT_PUBLIC_CLICKA_API_URL") || // Canonical host
|
|
806
|
+
return prop || readGlobalString("__CLICKA_ENGINE_URL") || readMeta("clicka:engine") || readEnv("NEXT_PUBLIC_ENGINE_URL") || readEnv("NEXT_PUBLIC_CLICKA_ENGINE") || readEnv("NEXT_PUBLIC_CLICKA_API_URL") || // Canonical engine host. Avoid bare-domain redirects in cross-origin fetches
|
|
789
807
|
// which kills cross-origin fetches because the redirect response itself
|
|
790
808
|
// carries no CORS headers — browsers reject the whole chain.
|
|
791
|
-
"https://
|
|
809
|
+
"https://app.alternine.co";
|
|
810
|
+
}
|
|
811
|
+
function resolveApiKey(prop) {
|
|
812
|
+
return prop || readGlobalString("__CLICKA_BOOKING_API_KEY") || readMeta("clicka:api-key") || readEnv("NEXT_PUBLIC_BOOKING_API_KEY") || readEnv("NEXT_PUBLIC_CLICKA_BOOKING_API_KEY");
|
|
792
813
|
}
|
|
793
814
|
function resolveLocale(prop) {
|
|
794
815
|
if (prop) return prop;
|
|
@@ -815,6 +836,7 @@ function BookingProvider({
|
|
|
815
836
|
children,
|
|
816
837
|
salonSlug,
|
|
817
838
|
engineUrl,
|
|
839
|
+
apiKey,
|
|
818
840
|
locale,
|
|
819
841
|
successUrl,
|
|
820
842
|
cancelUrl,
|
|
@@ -827,6 +849,7 @@ function BookingProvider({
|
|
|
827
849
|
}) {
|
|
828
850
|
const slug = useMemo(() => resolveSlug(salonSlug), [salonSlug]);
|
|
829
851
|
const resolvedEngineUrl = useMemo(() => resolveEngine(engineUrl), [engineUrl]);
|
|
852
|
+
const resolvedApiKey = useMemo(() => resolveApiKey(apiKey), [apiKey]);
|
|
830
853
|
const resolvedLocale = useMemo(() => resolveLocale(locale), [locale]);
|
|
831
854
|
const resolvedSuccessUrl = useMemo(
|
|
832
855
|
() => successUrl ?? defaultReturnUrl("booked"),
|
|
@@ -844,13 +867,16 @@ function BookingProvider({
|
|
|
844
867
|
useEffect(() => {
|
|
845
868
|
if (!slug) {
|
|
846
869
|
console.error(
|
|
847
|
-
'[@
|
|
870
|
+
'[@clicka1/booking] BookingProvider has no salon slug. Pass `salonSlug` or set NEXT_PUBLIC_SALON_SLUG / <meta name="clicka:salon"> / window.__CLICKA_SALON_SLUG.'
|
|
848
871
|
);
|
|
849
872
|
return;
|
|
850
873
|
}
|
|
851
874
|
let cancelled = false;
|
|
852
875
|
const url = `${resolvedEngineUrl.replace(/\/$/, "")}/api/public/v1/salons/${encodeURIComponent(slug)}`;
|
|
853
|
-
fetch(url, {
|
|
876
|
+
fetch(url, {
|
|
877
|
+
cache: "no-store",
|
|
878
|
+
headers: resolvedApiKey ? { "X-API-Key": resolvedApiKey } : void 0
|
|
879
|
+
}).then((r) => {
|
|
854
880
|
if (!r.ok) throw new Error(`Salon fetch failed: HTTP ${r.status}`);
|
|
855
881
|
return r.json();
|
|
856
882
|
}).then((d) => {
|
|
@@ -861,13 +887,13 @@ function BookingProvider({
|
|
|
861
887
|
}).catch((e) => {
|
|
862
888
|
if (cancelled) return;
|
|
863
889
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
864
|
-
console.error("[@
|
|
890
|
+
console.error("[@clicka1/booking] salon fetch failed:", err);
|
|
865
891
|
setError(err);
|
|
866
892
|
});
|
|
867
893
|
return () => {
|
|
868
894
|
cancelled = true;
|
|
869
895
|
};
|
|
870
|
-
}, [resolvedEngineUrl, slug]);
|
|
896
|
+
}, [resolvedApiKey, resolvedEngineUrl, slug]);
|
|
871
897
|
const open = useCallback(
|
|
872
898
|
(service) => {
|
|
873
899
|
if (widgetRef.current && salon) {
|
|
@@ -923,6 +949,7 @@ function BookingProvider({
|
|
|
923
949
|
slug,
|
|
924
950
|
salon,
|
|
925
951
|
engineUrl: resolvedEngineUrl,
|
|
952
|
+
apiKey: resolvedApiKey,
|
|
926
953
|
locale: resolvedLocale,
|
|
927
954
|
successUrl: resolvedSuccessUrl,
|
|
928
955
|
cancelUrl: resolvedCancelUrl,
|
|
@@ -941,7 +968,7 @@ function useBooking() {
|
|
|
941
968
|
const ctx = useContext(BookingContext);
|
|
942
969
|
if (!ctx) {
|
|
943
970
|
throw new Error(
|
|
944
|
-
"[@
|
|
971
|
+
"[@clicka1/booking] useBooking() must be called inside <BookingProvider>."
|
|
945
972
|
);
|
|
946
973
|
}
|
|
947
974
|
return ctx;
|