chore(frontend): format files with prettier

This commit is contained in:
Piotr Oleszczyk 2026-03-03 20:51:34 +01:00
parent 0e7a39836f
commit 067e460dd2
20 changed files with 1615 additions and 1509 deletions

10
frontend/.mcp.json Normal file
View file

@ -0,0 +1,10 @@
{
"mcpServers": {
"svelte": {
"type": "stdio",
"command": "npx",
"env": {},
"args": ["-y", "@sveltejs/mcp"]
}
}
}

View file

@ -24,8 +24,8 @@ The backend must be running at `http://localhost:8000`. See `../backend/` for se
## Environment variables ## Environment variables
| Variable | Description | Default | | Variable | Description | Default |
|---|---|---| | ----------------- | ------------------------------- | ----------------------- |
| `PUBLIC_API_BASE` | Base URL of the FastAPI backend | `http://localhost:8000` | | `PUBLIC_API_BASE` | Base URL of the FastAPI backend | `http://localhost:8000` |
Set `PUBLIC_API_BASE` at **build time** for production: Set `PUBLIC_API_BASE` at **build time** for production:
@ -51,24 +51,24 @@ Or use the provided systemd service: `../systemd/innercontext-node.service`.
## Routes ## Routes
| Route | Description | | Route | Description |
|---|---| | --------------------- | ------------------------ |
| `/` | Dashboard | | `/` | Dashboard |
| `/products` | Product list | | `/products` | Product list |
| `/products/new` | Add product | | `/products/new` | Add product |
| `/products/[id]` | Product detail / edit | | `/products/[id]` | Product detail / edit |
| `/routines` | Routine list | | `/routines` | Routine list |
| `/routines/new` | Create routine | | `/routines/new` | Create routine |
| `/routines/[id]` | Routine detail | | `/routines/[id]` | Routine detail |
| `/health/medications` | Medications | | `/health/medications` | Medications |
| `/health/lab-results` | Lab results | | `/health/lab-results` | Lab results |
| `/skin` | Skin condition snapshots | | `/skin` | Skin condition snapshots |
## Key files ## Key files
| File | Purpose | | File | Purpose |
|---|---| | ------------------ | --------------------------------- |
| `src/lib/api.ts` | API client (typed fetch wrappers) | | `src/lib/api.ts` | API client (typed fetch wrappers) |
| `src/lib/types.ts` | Shared TypeScript types | | `src/lib/types.ts` | Shared TypeScript types |
| `src/app.css` | Tailwind v4 theme + global styles | | `src/app.css` | Tailwind v4 theme + global styles |
| `svelte.config.js` | SvelteKit config (adapter-node) | | `svelte.config.js` | SvelteKit config (adapter-node) |

View file

@ -1,17 +1,17 @@
{ {
"$schema": "https://shadcn-svelte.com/schema.json", "$schema": "https://shadcn-svelte.com/schema.json",
"style": "default", "style": "default",
"tailwind": { "tailwind": {
"config": "", "config": "",
"css": "src/app.css", "css": "src/app.css",
"baseColor": "zinc" "baseColor": "zinc"
}, },
"aliases": { "aliases": {
"components": "$lib/components", "components": "$lib/components",
"utils": "$lib/utils", "utils": "$lib/utils",
"ui": "$lib/components/ui", "ui": "$lib/components/ui",
"hooks": "$lib/hooks", "hooks": "$lib/hooks",
"lib": "$lib" "lib": "$lib"
}, },
"registry": "https://shadcn-svelte.com/registry" "registry": "https://shadcn-svelte.com/registry"
} }

View file

@ -1,455 +1,455 @@
{ {
"nav_dashboard": "Dashboard", "nav_dashboard": "Dashboard",
"nav_products": "Products", "nav_products": "Products",
"nav_routines": "Routines", "nav_routines": "Routines",
"nav_grooming": "Grooming", "nav_grooming": "Grooming",
"nav_medications": "Medications", "nav_medications": "Medications",
"nav_labResults": "Lab Results", "nav_labResults": "Lab Results",
"nav_skin": "Skin", "nav_skin": "Skin",
"nav_appName": "innercontext", "nav_appName": "innercontext",
"nav_appSubtitle": "personal health & skincare", "nav_appSubtitle": "personal health & skincare",
"common_save": "Save", "common_save": "Save",
"common_cancel": "Cancel", "common_cancel": "Cancel",
"common_add": "Add", "common_add": "Add",
"common_edit": "Edit", "common_edit": "Edit",
"common_delete": "Delete", "common_delete": "Delete",
"common_saved": "Saved.", "common_saved": "Saved.",
"common_select": "Select", "common_select": "Select",
"common_unknown": "Unknown", "common_unknown": "Unknown",
"common_yes": "Yes", "common_yes": "Yes",
"common_no": "No", "common_no": "No",
"common_unknown_value": "Unknown", "common_unknown_value": "Unknown",
"common_optional_notes": "optional", "common_optional_notes": "optional",
"common_steps": "steps", "common_steps": "steps",
"dashboard_title": "Dashboard", "dashboard_title": "Dashboard",
"dashboard_subtitle": "Your recent health & skincare overview", "dashboard_subtitle": "Your recent health & skincare overview",
"dashboard_latestSnapshot": "Latest Skin Snapshot", "dashboard_latestSnapshot": "Latest Skin Snapshot",
"dashboard_recentRoutines": "Recent Routines", "dashboard_recentRoutines": "Recent Routines",
"dashboard_noSnapshots": "No skin snapshots yet.", "dashboard_noSnapshots": "No skin snapshots yet.",
"dashboard_noRoutines": "No routines in the past 2 weeks.", "dashboard_noRoutines": "No routines in the past 2 weeks.",
"products_title": "Products", "products_title": "Products",
"products_count": "{count} products", "products_count": "{count} products",
"products_addNew": "+ Add product", "products_addNew": "+ Add product",
"products_suggest": "Suggest", "products_suggest": "Suggest",
"products_suggestTitle": "Shopping suggestions", "products_suggestTitle": "Shopping suggestions",
"products_suggestSubtitle": "What to buy?", "products_suggestSubtitle": "What to buy?",
"products_suggestDescription": "Based on your skin condition and products you own, I'll suggest product types that could complement your routine.", "products_suggestDescription": "Based on your skin condition and products you own, I'll suggest product types that could complement your routine.",
"products_suggestGenerating": "Analyzing...", "products_suggestGenerating": "Analyzing...",
"products_suggestBtn": "Generate suggestions", "products_suggestBtn": "Generate suggestions",
"products_suggestResults": "Suggestions", "products_suggestResults": "Suggestions",
"products_suggestTime": "Time", "products_suggestTime": "Time",
"products_suggestFrequency": "Frequency", "products_suggestFrequency": "Frequency",
"products_suggestRegenerate": "Regenerate", "products_suggestRegenerate": "Regenerate",
"products_suggestNoResults": "No suggestions.", "products_suggestNoResults": "No suggestions.",
"products_noProducts": "No products found.", "products_noProducts": "No products found.",
"products_filterAll": "All", "products_filterAll": "All",
"products_filterOwned": "Owned", "products_filterOwned": "Owned",
"products_filterUnowned": "Not owned", "products_filterUnowned": "Not owned",
"products_colName": "Name", "products_colName": "Name",
"products_colBrand": "Brand", "products_colBrand": "Brand",
"products_colTargets": "Targets", "products_colTargets": "Targets",
"products_colTime": "Time", "products_colTime": "Time",
"products_newTitle": "New Product", "products_newTitle": "New Product",
"products_backToList": "← Products", "products_backToList": "← Products",
"products_createProduct": "Create product", "products_createProduct": "Create product",
"products_saveChanges": "Save changes", "products_saveChanges": "Save changes",
"products_deleteProduct": "Delete product", "products_deleteProduct": "Delete product",
"products_confirmDelete": "Delete this product?", "products_confirmDelete": "Delete this product?",
"products_noInventory": "No inventory packages.", "products_noInventory": "No inventory packages.",
"inventory_title": "Inventory packages ({count})", "inventory_title": "Inventory packages ({count})",
"inventory_addPackage": "+ Add package", "inventory_addPackage": "+ Add package",
"inventory_packageAdded": "Package added.", "inventory_packageAdded": "Package added.",
"inventory_packageUpdated": "Package updated.", "inventory_packageUpdated": "Package updated.",
"inventory_packageDeleted": "Package deleted.", "inventory_packageDeleted": "Package deleted.",
"inventory_alreadyOpened": "Already opened", "inventory_alreadyOpened": "Already opened",
"inventory_openedDate": "Opened date", "inventory_openedDate": "Opened date",
"inventory_finishedDate": "Finished date", "inventory_finishedDate": "Finished date",
"inventory_expiryDate": "Expiry date", "inventory_expiryDate": "Expiry date",
"inventory_currentWeight": "Current weight (g)", "inventory_currentWeight": "Current weight (g)",
"inventory_lastWeighed": "Last weighed", "inventory_lastWeighed": "Last weighed",
"inventory_notes": "Notes", "inventory_notes": "Notes",
"inventory_badgeOpen": "Open", "inventory_badgeOpen": "Open",
"inventory_badgeSealed": "Sealed", "inventory_badgeSealed": "Sealed",
"inventory_badgeFinished": "Finished", "inventory_badgeFinished": "Finished",
"inventory_exp": "Exp:", "inventory_exp": "Exp:",
"inventory_opened": "Opened:", "inventory_opened": "Opened:",
"inventory_finished": "Finished:", "inventory_finished": "Finished:",
"inventory_remaining": "g remaining", "inventory_remaining": "g remaining",
"inventory_weighed": "Weighed:", "inventory_weighed": "Weighed:",
"inventory_confirmDelete": "Delete this package?", "inventory_confirmDelete": "Delete this package?",
"routines_title": "Routines", "routines_title": "Routines",
"routines_count": "{count} routines (last 30 days)", "routines_count": "{count} routines (last 30 days)",
"routines_suggestAI": "Suggest AI routine", "routines_suggestAI": "Suggest AI routine",
"routines_addNew": "+ New routine", "routines_addNew": "+ New routine",
"routines_noRoutines": "No routines found.", "routines_noRoutines": "No routines found.",
"routines_newTitle": "New Routine", "routines_newTitle": "New Routine",
"routines_backToList": "← Routines", "routines_backToList": "← Routines",
"routines_detailsTitle": "Routine details", "routines_detailsTitle": "Routine details",
"routines_date": "Date *", "routines_date": "Date *",
"routines_amOrPm": "AM or PM *", "routines_amOrPm": "AM or PM *",
"routines_notes": "Notes", "routines_notes": "Notes",
"routines_notesPlaceholder": "Optional notes", "routines_notesPlaceholder": "Optional notes",
"routines_createRoutine": "Create routine", "routines_createRoutine": "Create routine",
"routines_deleteRoutine": "Delete routine", "routines_deleteRoutine": "Delete routine",
"routines_confirmDelete": "Delete this routine?", "routines_confirmDelete": "Delete this routine?",
"routines_steps": "Steps ({count})", "routines_steps": "Steps ({count})",
"routines_addStep": "+ Add step", "routines_addStep": "+ Add step",
"routines_addStepTitle": "Add step", "routines_addStepTitle": "Add step",
"routines_product": "Product", "routines_product": "Product",
"routines_selectProduct": "Select product", "routines_selectProduct": "Select product",
"routines_dose": "Dose", "routines_dose": "Dose",
"routines_dosePlaceholder": "e.g. 2 pumps", "routines_dosePlaceholder": "e.g. 2 pumps",
"routines_region": "Region", "routines_region": "Region",
"routines_regionPlaceholder": "e.g. face", "routines_regionPlaceholder": "e.g. face",
"routines_addStepBtn": "Add step", "routines_addStepBtn": "Add step",
"routines_unknownStep": "Unknown step", "routines_unknownStep": "Unknown step",
"routines_noSteps": "No steps yet.", "routines_noSteps": "No steps yet.",
"grooming_title": "Grooming Schedule", "grooming_title": "Grooming Schedule",
"grooming_backToRoutines": "← Routines", "grooming_backToRoutines": "← Routines",
"grooming_addEntry": "+ Add entry", "grooming_addEntry": "+ Add entry",
"grooming_entryAdded": "Entry added.", "grooming_entryAdded": "Entry added.",
"grooming_entryUpdated": "Entry updated.", "grooming_entryUpdated": "Entry updated.",
"grooming_entryDeleted": "Entry deleted.", "grooming_entryDeleted": "Entry deleted.",
"grooming_dayOfWeek": "Day of week", "grooming_dayOfWeek": "Day of week",
"grooming_action": "Action", "grooming_action": "Action",
"grooming_notesOptional": "Notes (optional)", "grooming_notesOptional": "Notes (optional)",
"grooming_notesPlaceholder": "e.g. every 2 weeks", "grooming_notesPlaceholder": "e.g. every 2 weeks",
"grooming_noEntries": "No entries yet. Click \"+ Add entry\" to get started.", "grooming_noEntries": "No entries yet. Click \"+ Add entry\" to get started.",
"grooming_confirmDelete": "Delete this entry?", "grooming_confirmDelete": "Delete this entry?",
"grooming_actionShavingRazor": "Razor shaving", "grooming_actionShavingRazor": "Razor shaving",
"grooming_actionShavingOneblade": "OneBlade shaving", "grooming_actionShavingOneblade": "OneBlade shaving",
"grooming_actionDermarolling": "Dermarolling", "grooming_actionDermarolling": "Dermarolling",
"grooming_dayMonday": "Monday", "grooming_dayMonday": "Monday",
"grooming_dayTuesday": "Tuesday", "grooming_dayTuesday": "Tuesday",
"grooming_dayWednesday": "Wednesday", "grooming_dayWednesday": "Wednesday",
"grooming_dayThursday": "Thursday", "grooming_dayThursday": "Thursday",
"grooming_dayFriday": "Friday", "grooming_dayFriday": "Friday",
"grooming_daySaturday": "Saturday", "grooming_daySaturday": "Saturday",
"grooming_daySunday": "Sunday", "grooming_daySunday": "Sunday",
"suggest_title": "AI Routine Suggestion", "suggest_title": "AI Routine Suggestion",
"suggest_backToRoutines": "← Routines", "suggest_backToRoutines": "← Routines",
"suggest_singleTab": "Single routine", "suggest_singleTab": "Single routine",
"suggest_batchTab": "Batch / Vacation", "suggest_batchTab": "Batch / Vacation",
"suggest_singleParams": "Parameters", "suggest_singleParams": "Parameters",
"suggest_date": "Date", "suggest_date": "Date",
"suggest_timeOfDay": "Time of day", "suggest_timeOfDay": "Time of day",
"suggest_contextLabel": "Additional context for AI", "suggest_contextLabel": "Additional context for AI",
"suggest_contextOptional": "(optional)", "suggest_contextOptional": "(optional)",
"suggest_contextPlaceholder": "e.g. party night, focusing on hydration...", "suggest_contextPlaceholder": "e.g. party night, focusing on hydration...",
"suggest_leavingHomeLabel": "Going outside today", "suggest_leavingHomeLabel": "Going outside today",
"suggest_leavingHomeHint": "Affects SPF selection — checked: SPF50+, unchecked: SPF30.", "suggest_leavingHomeHint": "Affects SPF selection — checked: SPF50+, unchecked: SPF30.",
"suggest_minoxidilToggleLabel": "Prioritize beard/mustache density (minoxidil)", "suggest_minoxidilToggleLabel": "Prioritize beard/mustache density (minoxidil)",
"suggest_minoxidilToggleHint": "When enabled, AI will explicitly consider minoxidil for beard/mustache areas if available.", "suggest_minoxidilToggleHint": "When enabled, AI will explicitly consider minoxidil for beard/mustache areas if available.",
"suggest_generateBtn": "Generate suggestion", "suggest_generateBtn": "Generate suggestion",
"suggest_generating": "Generating…", "suggest_generating": "Generating…",
"suggest_proposalTitle": "Suggestion", "suggest_proposalTitle": "Suggestion",
"suggest_saveRoutine": "Save routine", "suggest_saveRoutine": "Save routine",
"suggest_saving": "Saving…", "suggest_saving": "Saving…",
"suggest_regenerate": "Regenerate", "suggest_regenerate": "Regenerate",
"suggest_batchRange": "Date range", "suggest_batchRange": "Date range",
"suggest_fromDate": "From", "suggest_fromDate": "From",
"suggest_toDate": "To (max 14 days)", "suggest_toDate": "To (max 14 days)",
"suggest_batchContextLabel": "Context / trip purpose", "suggest_batchContextLabel": "Context / trip purpose",
"suggest_batchContextPlaceholder": "e.g. sunny trip to Italy, active mountain vacation...", "suggest_batchContextPlaceholder": "e.g. sunny trip to Italy, active mountain vacation...",
"suggest_generatePlan": "Generate plan", "suggest_generatePlan": "Generate plan",
"suggest_generatingPlan": "Generating plan…", "suggest_generatingPlan": "Generating plan…",
"suggest_planTitle": "Plan ({count} days)", "suggest_planTitle": "Plan ({count} days)",
"suggest_saveAllRoutines": "Save all routines", "suggest_saveAllRoutines": "Save all routines",
"suggest_amSteps": "steps", "suggest_amSteps": "steps",
"suggest_pmSteps": "steps", "suggest_pmSteps": "steps",
"suggest_noAmSteps": "No AM steps.", "suggest_noAmSteps": "No AM steps.",
"suggest_noPmSteps": "No PM steps.", "suggest_noPmSteps": "No PM steps.",
"suggest_errorDefault": "Error generating suggestion.", "suggest_errorDefault": "Error generating suggestion.",
"suggest_errorBatch": "Error generating plan.", "suggest_errorBatch": "Error generating plan.",
"suggest_errorSave": "Error saving.", "suggest_errorSave": "Error saving.",
"suggest_amMorning": "AM (morning)", "suggest_amMorning": "AM (morning)",
"suggest_pmEvening": "PM (evening)", "suggest_pmEvening": "PM (evening)",
"medications_title": "Medications", "medications_title": "Medications",
"medications_count": "{count} entries", "medications_count": "{count} entries",
"medications_addNew": "+ Add medication", "medications_addNew": "+ Add medication",
"medications_newTitle": "New medication", "medications_newTitle": "New medication",
"medications_kind": "Kind", "medications_kind": "Kind",
"medications_productName": "Product name *", "medications_productName": "Product name *",
"medications_productNamePlaceholder": "e.g. Vitamin D3", "medications_productNamePlaceholder": "e.g. Vitamin D3",
"medications_activeSubstance": "Active substance", "medications_activeSubstance": "Active substance",
"medications_activeSubstancePlaceholder": "e.g. cholecalciferol", "medications_activeSubstancePlaceholder": "e.g. cholecalciferol",
"medications_notes": "Notes", "medications_notes": "Notes",
"medications_added": "Medication added.", "medications_added": "Medication added.",
"medications_usages": "{count} usages", "medications_usages": "{count} usages",
"medications_noMedications": "No medications recorded.", "medications_noMedications": "No medications recorded.",
"medications_kindPrescription": "Prescription", "medications_kindPrescription": "Prescription",
"medications_kindOtc": "OTC", "medications_kindOtc": "OTC",
"medications_kindSupplement": "Supplement", "medications_kindSupplement": "Supplement",
"medications_kindHerbal": "Herbal", "medications_kindHerbal": "Herbal",
"medications_kindOther": "Other", "medications_kindOther": "Other",
"labResults_title": "Lab Results", "labResults_title": "Lab Results",
"labResults_count": "{count} results", "labResults_count": "{count} results",
"labResults_addNew": "+ Add result", "labResults_addNew": "+ Add result",
"labResults_newTitle": "New lab result", "labResults_newTitle": "New lab result",
"labResults_flagFilter": "Flag:", "labResults_flagFilter": "Flag:",
"labResults_flagAll": "All", "labResults_flagAll": "All",
"labResults_flagNone": "None", "labResults_flagNone": "None",
"labResults_date": "Date *", "labResults_date": "Date *",
"labResults_loincCode": "LOINC code *", "labResults_loincCode": "LOINC code *",
"labResults_testName": "Test name", "labResults_testName": "Test name",
"labResults_testNamePlaceholder": "e.g. Hemoglobin", "labResults_testNamePlaceholder": "e.g. Hemoglobin",
"labResults_lab": "Lab", "labResults_lab": "Lab",
"labResults_labPlaceholder": "e.g. LabCorp", "labResults_labPlaceholder": "e.g. LabCorp",
"labResults_value": "Value", "labResults_value": "Value",
"labResults_unit": "Unit", "labResults_unit": "Unit",
"labResults_unitPlaceholder": "e.g. g/dL", "labResults_unitPlaceholder": "e.g. g/dL",
"labResults_flag": "Flag", "labResults_flag": "Flag",
"labResults_added": "Result added.", "labResults_added": "Result added.",
"labResults_colDate": "Date", "labResults_colDate": "Date",
"labResults_colTest": "Test", "labResults_colTest": "Test",
"labResults_colLoinc": "LOINC", "labResults_colLoinc": "LOINC",
"labResults_colValue": "Value", "labResults_colValue": "Value",
"labResults_colFlag": "Flag", "labResults_colFlag": "Flag",
"labResults_colLab": "Lab", "labResults_colLab": "Lab",
"labResults_noResults": "No lab results found.", "labResults_noResults": "No lab results found.",
"skin_title": "Skin Snapshots", "skin_title": "Skin Snapshots",
"skin_count": "{count} snapshots", "skin_count": "{count} snapshots",
"skin_addNew": "+ Add snapshot", "skin_addNew": "+ Add snapshot",
"skin_aiAnalysisTitle": "AI analysis from photos", "skin_aiAnalysisTitle": "AI analysis from photos",
"skin_aiUploadText": "Upload 13 photos of your skin. AI will pre-fill the form fields below.", "skin_aiUploadText": "Upload 13 photos of your skin. AI will pre-fill the form fields below.",
"skin_analyzePhotos": "Analyze photos", "skin_analyzePhotos": "Analyze photos",
"skin_analyzing": "Analyzing…", "skin_analyzing": "Analyzing…",
"skin_newSnapshotTitle": "New skin snapshot", "skin_newSnapshotTitle": "New skin snapshot",
"skin_date": "Date *", "skin_date": "Date *",
"skin_overallState": "Overall state", "skin_overallState": "Overall state",
"skin_texture": "Texture", "skin_texture": "Texture",
"skin_skinType": "Skin type", "skin_skinType": "Skin type",
"skin_barrierState": "Barrier state", "skin_barrierState": "Barrier state",
"skin_hydration": "Hydration (15)", "skin_hydration": "Hydration (15)",
"skin_sensitivity": "Sensitivity (15)", "skin_sensitivity": "Sensitivity (15)",
"skin_sebumTzone": "Sebum T-zone (15)", "skin_sebumTzone": "Sebum T-zone (15)",
"skin_sebumCheeks": "Sebum cheeks (15)", "skin_sebumCheeks": "Sebum cheeks (15)",
"skin_activeConcerns": "Active concerns (comma-separated)", "skin_activeConcerns": "Active concerns (comma-separated)",
"skin_activeConcernsPlaceholder": "acne, redness, dehydration", "skin_activeConcernsPlaceholder": "acne, redness, dehydration",
"skin_priorities": "Priorities (comma-separated)", "skin_priorities": "Priorities (comma-separated)",
"skin_prioritiesPlaceholder": "strengthen barrier, reduce redness", "skin_prioritiesPlaceholder": "strengthen barrier, reduce redness",
"skin_prioritiesLabel": "Priorities", "skin_prioritiesLabel": "Priorities",
"skin_notes": "Notes", "skin_notes": "Notes",
"skin_addSnapshot": "Add snapshot", "skin_addSnapshot": "Add snapshot",
"skin_snapshotAdded": "Snapshot added.", "skin_snapshotAdded": "Snapshot added.",
"skin_snapshotUpdated": "Snapshot updated.", "skin_snapshotUpdated": "Snapshot updated.",
"skin_snapshotDeleted": "Snapshot deleted.", "skin_snapshotDeleted": "Snapshot deleted.",
"skin_noSnapshots": "No skin snapshots yet.", "skin_noSnapshots": "No skin snapshots yet.",
"skin_hydrationLabel": "Hydration", "skin_hydrationLabel": "Hydration",
"skin_sensitivityLabel": "Sensitivity", "skin_sensitivityLabel": "Sensitivity",
"skin_barrierLabel": "Barrier", "skin_barrierLabel": "Barrier",
"skin_stateExcellent": "excellent", "skin_stateExcellent": "excellent",
"skin_stateGood": "good", "skin_stateGood": "good",
"skin_stateFair": "fair", "skin_stateFair": "fair",
"skin_statePoor": "poor", "skin_statePoor": "poor",
"skin_textureSmooth": "smooth", "skin_textureSmooth": "smooth",
"skin_textureRough": "rough", "skin_textureRough": "rough",
"skin_textureFlaky": "flaky", "skin_textureFlaky": "flaky",
"skin_textureBumpy": "bumpy", "skin_textureBumpy": "bumpy",
"skin_barrierIntact": "intact", "skin_barrierIntact": "intact",
"skin_barrierMildly": "mildly compromised", "skin_barrierMildly": "mildly compromised",
"skin_barrierCompromised": "compromised", "skin_barrierCompromised": "compromised",
"skin_typeDry": "dry", "skin_typeDry": "dry",
"skin_typeOily": "oily", "skin_typeOily": "oily",
"skin_typeCombination": "combination", "skin_typeCombination": "combination",
"skin_typeSensitive": "sensitive", "skin_typeSensitive": "sensitive",
"skin_typeNormal": "normal", "skin_typeNormal": "normal",
"skin_typeAcneProne": "acne prone", "skin_typeAcneProne": "acne prone",
"productForm_aiPrefill": "AI pre-fill", "productForm_aiPrefill": "AI pre-fill",
"productForm_aiPrefillText": "Paste product description from a website, ingredient list, or other text. AI will fill in available fields — you can review and correct before saving.", "productForm_aiPrefillText": "Paste product description from a website, ingredient list, or other text. AI will fill in available fields — you can review and correct before saving.",
"productForm_pasteText": "Paste product description, INCI ingredients here...", "productForm_pasteText": "Paste product description, INCI ingredients here...",
"productForm_parseWithAI": "Fill fields (AI)", "productForm_parseWithAI": "Fill fields (AI)",
"productForm_parsing": "Processing…", "productForm_parsing": "Processing…",
"productForm_basicInfo": "Basic info", "productForm_basicInfo": "Basic info",
"productForm_name": "Name *", "productForm_name": "Name *",
"productForm_namePlaceholder": "e.g. Hydro Boost Water Gel", "productForm_namePlaceholder": "e.g. Hydro Boost Water Gel",
"productForm_brand": "Brand *", "productForm_brand": "Brand *",
"productForm_brandPlaceholder": "e.g. Neutrogena", "productForm_brandPlaceholder": "e.g. Neutrogena",
"productForm_lineName": "Line / series", "productForm_lineName": "Line / series",
"productForm_lineNamePlaceholder": "e.g. Hydro Boost", "productForm_lineNamePlaceholder": "e.g. Hydro Boost",
"productForm_url": "URL", "productForm_url": "URL",
"productForm_sku": "SKU", "productForm_sku": "SKU",
"productForm_skuPlaceholder": "e.g. NTR-HB-50", "productForm_skuPlaceholder": "e.g. NTR-HB-50",
"productForm_barcode": "Barcode / EAN", "productForm_barcode": "Barcode / EAN",
"productForm_barcodePlaceholder": "e.g. 3614273258975", "productForm_barcodePlaceholder": "e.g. 3614273258975",
"productForm_classification": "Classification", "productForm_classification": "Classification",
"productForm_category": "Category *", "productForm_category": "Category *",
"productForm_selectCategory": "Select category", "productForm_selectCategory": "Select category",
"productForm_time": "Time *", "productForm_time": "Time *",
"productForm_timeOptions": "AM / PM / Both", "productForm_timeOptions": "AM / PM / Both",
"productForm_timeBoth": "Both", "productForm_timeBoth": "Both",
"productForm_leaveOn": "Leave-on *", "productForm_leaveOn": "Leave-on *",
"productForm_leaveOnYes": "Yes (leave-on)", "productForm_leaveOnYes": "Yes (leave-on)",
"productForm_leaveOnNo": "No (rinse-off)", "productForm_leaveOnNo": "No (rinse-off)",
"productForm_texture": "Texture", "productForm_texture": "Texture",
"productForm_selectTexture": "Select texture", "productForm_selectTexture": "Select texture",
"productForm_absorptionSpeed": "Absorption speed", "productForm_absorptionSpeed": "Absorption speed",
"productForm_selectSpeed": "Select speed", "productForm_selectSpeed": "Select speed",
"productForm_skinProfile": "Skin profile", "productForm_skinProfile": "Skin profile",
"productForm_recommendedFor": "Recommended for skin types", "productForm_recommendedFor": "Recommended for skin types",
"productForm_targetConcerns": "Target concerns", "productForm_targetConcerns": "Target concerns",
"productForm_contraindications": "Contraindications (one per line)", "productForm_contraindications": "Contraindications (one per line)",
"productForm_contraindicationsPlaceholder": "e.g. active rosacea flares", "productForm_contraindicationsPlaceholder": "e.g. active rosacea flares",
"productForm_ingredients": "Ingredients", "productForm_ingredients": "Ingredients",
"productForm_inciList": "INCI list (one ingredient per line)", "productForm_inciList": "INCI list (one ingredient per line)",
"productForm_activeIngredients": "Active ingredients", "productForm_activeIngredients": "Active ingredients",
"productForm_addActive": "+ Add active", "productForm_addActive": "+ Add active",
"productForm_noActives": "No actives added yet.", "productForm_noActives": "No actives added yet.",
"productForm_activeName": "Name", "productForm_activeName": "Name",
"productForm_activePercent": "%", "productForm_activePercent": "%",
"productForm_activeStrength": "Strength", "productForm_activeStrength": "Strength",
"productForm_activeIrritation": "Irritation", "productForm_activeIrritation": "Irritation",
"productForm_activeFunctions": "Functions", "productForm_activeFunctions": "Functions",
"productForm_effectProfile": "Effect profile (05)", "productForm_effectProfile": "Effect profile (05)",
"productForm_interactions": "Interactions", "productForm_interactions": "Interactions",
"productForm_synergizesWith": "Synergizes with (one per line)", "productForm_synergizesWith": "Synergizes with (one per line)",
"productForm_incompatibleWith": "Incompatible with", "productForm_incompatibleWith": "Incompatible with",
"productForm_addIncompatibility": "+ Add incompatibility", "productForm_addIncompatibility": "+ Add incompatibility",
"productForm_noIncompatibilities": "No incompatibilities added.", "productForm_noIncompatibilities": "No incompatibilities added.",
"productForm_incompTarget": "Target ingredient", "productForm_incompTarget": "Target ingredient",
"productForm_incompScope": "Scope", "productForm_incompScope": "Scope",
"productForm_incompReason": "Reason (optional)", "productForm_incompReason": "Reason (optional)",
"productForm_incompReasonPlaceholder": "e.g. reduces efficacy", "productForm_incompReasonPlaceholder": "e.g. reduces efficacy",
"productForm_incompScopeSelect": "Select…", "productForm_incompScopeSelect": "Select…",
"productForm_contextRules": "Context rules", "productForm_contextRules": "Context rules",
"productForm_ctxAfterShaving": "Safe after shaving", "productForm_ctxAfterShaving": "Safe after shaving",
"productForm_ctxAfterAcids": "Safe after acids", "productForm_ctxAfterAcids": "Safe after acids",
"productForm_ctxAfterRetinoids": "Safe after retinoids", "productForm_ctxAfterRetinoids": "Safe after retinoids",
"productForm_ctxCompromisedBarrier": "Safe with compromised barrier", "productForm_ctxCompromisedBarrier": "Safe with compromised barrier",
"productForm_ctxLowUvOnly": "Low UV only (evening/covered)", "productForm_ctxLowUvOnly": "Low UV only (evening/covered)",
"productForm_productDetails": "Product details", "productForm_productDetails": "Product details",
"productForm_priceTier": "Price tier", "productForm_priceTier": "Price tier",
"productForm_selectTier": "Select tier", "productForm_selectTier": "Select tier",
"productForm_sizeMl": "Size (ml)", "productForm_sizeMl": "Size (ml)",
"productForm_fullWeightG": "Full weight (g)", "productForm_fullWeightG": "Full weight (g)",
"productForm_emptyWeightG": "Empty weight (g)", "productForm_emptyWeightG": "Empty weight (g)",
"productForm_paoMonths": "PAO (months)", "productForm_paoMonths": "PAO (months)",
"productForm_phMin": "pH min", "productForm_phMin": "pH min",
"productForm_phMax": "pH max", "productForm_phMax": "pH max",
"productForm_usageNotes": "Usage notes", "productForm_usageNotes": "Usage notes",
"productForm_usageNotesPlaceholder": "e.g. Apply to damp skin, avoid eye area", "productForm_usageNotesPlaceholder": "e.g. Apply to damp skin, avoid eye area",
"productForm_safetyFlags": "Safety flags", "productForm_safetyFlags": "Safety flags",
"productForm_fragranceFree": "Fragrance-free", "productForm_fragranceFree": "Fragrance-free",
"productForm_essentialOilsFree": "Essential oils-free", "productForm_essentialOilsFree": "Essential oils-free",
"productForm_alcoholDenatFree": "Alcohol denat-free", "productForm_alcoholDenatFree": "Alcohol denat-free",
"productForm_pregnancySafe": "Pregnancy safe", "productForm_pregnancySafe": "Pregnancy safe",
"productForm_usageConstraints": "Usage constraints", "productForm_usageConstraints": "Usage constraints",
"productForm_minIntervalHours": "Min interval (hours)", "productForm_minIntervalHours": "Min interval (hours)",
"productForm_maxFrequencyPerWeek": "Max uses per week", "productForm_maxFrequencyPerWeek": "Max uses per week",
"productForm_isMedication": "Is medication", "productForm_isMedication": "Is medication",
"productForm_isTool": "Is tool (e.g. dermaroller)", "productForm_isTool": "Is tool (e.g. dermaroller)",
"productForm_needleLengthMm": "Needle length (mm, tools only)", "productForm_needleLengthMm": "Needle length (mm, tools only)",
"productForm_personalNotes": "Personal notes", "productForm_personalNotes": "Personal notes",
"productForm_repurchaseIntent": "Repurchase intent", "productForm_repurchaseIntent": "Repurchase intent",
"productForm_toleranceNotes": "Tolerance notes", "productForm_toleranceNotes": "Tolerance notes",
"productForm_toleranceNotesPlaceholder": "e.g. Causes mild stinging, fine after 2 weeks", "productForm_toleranceNotesPlaceholder": "e.g. Causes mild stinging, fine after 2 weeks",
"productForm_categoryCleanser": "Cleanser", "productForm_categoryCleanser": "Cleanser",
"productForm_categoryToner": "Toner", "productForm_categoryToner": "Toner",
"productForm_categoryEssence": "Essence", "productForm_categoryEssence": "Essence",
"productForm_categorySerum": "Serum", "productForm_categorySerum": "Serum",
"productForm_categoryMoisturizer": "Moisturizer", "productForm_categoryMoisturizer": "Moisturizer",
"productForm_categorySpf": "SPF", "productForm_categorySpf": "SPF",
"productForm_categoryMask": "Mask", "productForm_categoryMask": "Mask",
"productForm_categoryExfoliant": "Exfoliant", "productForm_categoryExfoliant": "Exfoliant",
"productForm_categoryHairTreatment": "Hair treatment", "productForm_categoryHairTreatment": "Hair treatment",
"productForm_categoryTool": "Tool", "productForm_categoryTool": "Tool",
"productForm_categorySpotTreatment": "Spot treatment", "productForm_categorySpotTreatment": "Spot treatment",
"productForm_categoryOil": "Oil", "productForm_categoryOil": "Oil",
"productForm_textureWatery": "Watery", "productForm_textureWatery": "Watery",
"productForm_textureGel": "Gel", "productForm_textureGel": "Gel",
"productForm_textureEmulsion": "Emulsion", "productForm_textureEmulsion": "Emulsion",
"productForm_textureCream": "Cream", "productForm_textureCream": "Cream",
"productForm_textureOil": "Oil", "productForm_textureOil": "Oil",
"productForm_textureBalm": "Balm", "productForm_textureBalm": "Balm",
"productForm_textureFoam": "Foam", "productForm_textureFoam": "Foam",
"productForm_textureFluid": "Fluid", "productForm_textureFluid": "Fluid",
"productForm_absorptionVeryFast": "Very fast", "productForm_absorptionVeryFast": "Very fast",
"productForm_absorptionFast": "Fast", "productForm_absorptionFast": "Fast",
"productForm_absorptionModerate": "Moderate", "productForm_absorptionModerate": "Moderate",
"productForm_absorptionSlow": "Slow", "productForm_absorptionSlow": "Slow",
"productForm_absorptionVerySlow": "Very slow", "productForm_absorptionVerySlow": "Very slow",
"productForm_priceBudget": "Budget", "productForm_priceBudget": "Budget",
"productForm_priceMid": "Mid", "productForm_priceMid": "Mid",
"productForm_pricePremium": "Premium", "productForm_pricePremium": "Premium",
"productForm_priceLuxury": "Luxury", "productForm_priceLuxury": "Luxury",
"productForm_skinTypeDry": "dry", "productForm_skinTypeDry": "dry",
"productForm_skinTypeOily": "oily", "productForm_skinTypeOily": "oily",
"productForm_skinTypeCombination": "combination", "productForm_skinTypeCombination": "combination",
"productForm_skinTypeSensitive": "sensitive", "productForm_skinTypeSensitive": "sensitive",
"productForm_skinTypeNormal": "normal", "productForm_skinTypeNormal": "normal",
"productForm_skinTypeAcneProne": "acne prone", "productForm_skinTypeAcneProne": "acne prone",
"productForm_concernAcne": "acne", "productForm_concernAcne": "acne",
"productForm_concernRosacea": "rosacea", "productForm_concernRosacea": "rosacea",
"productForm_concernHyperpigmentation": "hyperpigmentation", "productForm_concernHyperpigmentation": "hyperpigmentation",
"productForm_concernAging": "aging", "productForm_concernAging": "aging",
"productForm_concernDehydration": "dehydration", "productForm_concernDehydration": "dehydration",
"productForm_concernRedness": "redness", "productForm_concernRedness": "redness",
"productForm_concernDamagedBarrier": "damaged barrier", "productForm_concernDamagedBarrier": "damaged barrier",
"productForm_concernPoreVisibility": "pore visibility", "productForm_concernPoreVisibility": "pore visibility",
"productForm_concernUnevenTexture": "uneven texture", "productForm_concernUnevenTexture": "uneven texture",
"productForm_concernHairGrowth": "hair growth", "productForm_concernHairGrowth": "hair growth",
"productForm_concernSebumExcess": "sebum excess", "productForm_concernSebumExcess": "sebum excess",
"productForm_fnHumectant": "humectant", "productForm_fnHumectant": "humectant",
"productForm_fnEmollient": "emollient", "productForm_fnEmollient": "emollient",
"productForm_fnOcclusive": "occlusive", "productForm_fnOcclusive": "occlusive",
"productForm_fnExfoliantAha": "AHA exfoliant", "productForm_fnExfoliantAha": "AHA exfoliant",
"productForm_fnExfoliantBha": "BHA exfoliant", "productForm_fnExfoliantBha": "BHA exfoliant",
"productForm_fnExfoliantPha": "PHA exfoliant", "productForm_fnExfoliantPha": "PHA exfoliant",
"productForm_fnRetinoid": "retinoid", "productForm_fnRetinoid": "retinoid",
"productForm_fnAntioxidant": "antioxidant", "productForm_fnAntioxidant": "antioxidant",
"productForm_fnSoothing": "soothing", "productForm_fnSoothing": "soothing",
"productForm_fnBarrierSupport": "barrier support", "productForm_fnBarrierSupport": "barrier support",
"productForm_fnBrightening": "brightening", "productForm_fnBrightening": "brightening",
"productForm_fnAntiAcne": "anti-acne", "productForm_fnAntiAcne": "anti-acne",
"productForm_fnCeramide": "ceramide", "productForm_fnCeramide": "ceramide",
"productForm_fnNiacinamide": "niacinamide", "productForm_fnNiacinamide": "niacinamide",
"productForm_fnSunscreen": "sunscreen", "productForm_fnSunscreen": "sunscreen",
"productForm_fnPeptide": "peptide", "productForm_fnPeptide": "peptide",
"productForm_fnHairGrowth": "hair growth stimulant", "productForm_fnHairGrowth": "hair growth stimulant",
"productForm_fnPrebiotic": "prebiotic", "productForm_fnPrebiotic": "prebiotic",
"productForm_fnVitaminC": "vitamin C", "productForm_fnVitaminC": "vitamin C",
"productForm_fnAntiAging": "anti-aging", "productForm_fnAntiAging": "anti-aging",
"productForm_scopeSameStep": "same step", "productForm_scopeSameStep": "same step",
"productForm_scopeSameDay": "same day", "productForm_scopeSameDay": "same day",
"productForm_scopeSamePeriod": "same period", "productForm_scopeSamePeriod": "same period",
"productForm_strengthLow": "1 Low", "productForm_strengthLow": "1 Low",
"productForm_strengthMedium": "2 Medium", "productForm_strengthMedium": "2 Medium",
"productForm_strengthHigh": "3 High", "productForm_strengthHigh": "3 High",
"productForm_effectHydrationImmediate": "Hydration (immediate)", "productForm_effectHydrationImmediate": "Hydration (immediate)",
"productForm_effectHydrationLongTerm": "Hydration (long term)", "productForm_effectHydrationLongTerm": "Hydration (long term)",
"productForm_effectBarrierRepair": "Barrier repair", "productForm_effectBarrierRepair": "Barrier repair",
"productForm_effectSoothing": "Soothing", "productForm_effectSoothing": "Soothing",
"productForm_effectExfoliation": "Exfoliation", "productForm_effectExfoliation": "Exfoliation",
"productForm_effectRetinoid": "Retinoid activity", "productForm_effectRetinoid": "Retinoid activity",
"productForm_effectIrritation": "Irritation risk", "productForm_effectIrritation": "Irritation risk",
"productForm_effectComedogenic": "Comedogenic risk", "productForm_effectComedogenic": "Comedogenic risk",
"productForm_effectBarrierDisruption": "Barrier disruption risk", "productForm_effectBarrierDisruption": "Barrier disruption risk",
"productForm_effectDryness": "Dryness risk", "productForm_effectDryness": "Dryness risk",
"productForm_effectBrightening": "Brightening", "productForm_effectBrightening": "Brightening",
"productForm_effectAntiAcne": "Anti-acne", "productForm_effectAntiAcne": "Anti-acne",
"productForm_effectAntiAging": "Anti-aging", "productForm_effectAntiAging": "Anti-aging",
"lang_pl": "PL", "lang_pl": "PL",
"lang_en": "EN" "lang_en": "EN"
} }

View file

@ -1,455 +1,455 @@
{ {
"nav_dashboard": "Dashboard", "nav_dashboard": "Dashboard",
"nav_products": "Produkty", "nav_products": "Produkty",
"nav_routines": "Rutyny", "nav_routines": "Rutyny",
"nav_grooming": "Pielęgnacja", "nav_grooming": "Pielęgnacja",
"nav_medications": "Leki", "nav_medications": "Leki",
"nav_labResults": "Wyniki badań", "nav_labResults": "Wyniki badań",
"nav_skin": "Skóra", "nav_skin": "Skóra",
"nav_appName": "innercontext", "nav_appName": "innercontext",
"nav_appSubtitle": "zdrowie & pielęgnacja", "nav_appSubtitle": "zdrowie & pielęgnacja",
"common_save": "Zapisz", "common_save": "Zapisz",
"common_cancel": "Anuluj", "common_cancel": "Anuluj",
"common_add": "Dodaj", "common_add": "Dodaj",
"common_edit": "Edytuj", "common_edit": "Edytuj",
"common_delete": "Usuń", "common_delete": "Usuń",
"common_saved": "Zapisano.", "common_saved": "Zapisano.",
"common_select": "Wybierz", "common_select": "Wybierz",
"common_unknown": "Nieznane", "common_unknown": "Nieznane",
"common_yes": "Tak", "common_yes": "Tak",
"common_no": "Nie", "common_no": "Nie",
"common_unknown_value": "Nieznane", "common_unknown_value": "Nieznane",
"common_optional_notes": "opcjonalnie", "common_optional_notes": "opcjonalnie",
"common_steps": "kroków", "common_steps": "kroków",
"dashboard_title": "Dashboard", "dashboard_title": "Dashboard",
"dashboard_subtitle": "Przegląd zdrowia i pielęgnacji", "dashboard_subtitle": "Przegląd zdrowia i pielęgnacji",
"dashboard_latestSnapshot": "Ostatni stan skóry", "dashboard_latestSnapshot": "Ostatni stan skóry",
"dashboard_recentRoutines": "Ostatnie rutyny", "dashboard_recentRoutines": "Ostatnie rutyny",
"dashboard_noSnapshots": "Brak wpisów o stanie skóry.", "dashboard_noSnapshots": "Brak wpisów o stanie skóry.",
"dashboard_noRoutines": "Brak rutyno w ciągu ostatnich 2 tygodni.", "dashboard_noRoutines": "Brak rutyno w ciągu ostatnich 2 tygodni.",
"products_title": "Produkty", "products_title": "Produkty",
"products_count": "{count} produktów", "products_count": "{count} produktów",
"products_addNew": "+ Dodaj produkt", "products_addNew": "+ Dodaj produkt",
"products_suggest": "Sugeruj", "products_suggest": "Sugeruj",
"products_suggestTitle": "Sugestie zakupowe", "products_suggestTitle": "Sugestie zakupowe",
"products_suggestSubtitle": "Co warto kupić?", "products_suggestSubtitle": "Co warto kupić?",
"products_suggestDescription": "Na podstawie Twojego stanu skóry i posiadanych produktów zasugeruję typy produktów, które mogłyby uzupełnić Twoją rutynę.", "products_suggestDescription": "Na podstawie Twojego stanu skóry i posiadanych produktów zasugeruję typy produktów, które mogłyby uzupełnić Twoją rutynę.",
"products_suggestGenerating": "Analizuję...", "products_suggestGenerating": "Analizuję...",
"products_suggestBtn": "Generuj sugestie", "products_suggestBtn": "Generuj sugestie",
"products_suggestResults": "Propozycje", "products_suggestResults": "Propozycje",
"products_suggestTime": "Pora", "products_suggestTime": "Pora",
"products_suggestFrequency": "Częstotliwość", "products_suggestFrequency": "Częstotliwość",
"products_suggestRegenerate": "Wygeneruj ponownie", "products_suggestRegenerate": "Wygeneruj ponownie",
"products_suggestNoResults": "Brak propozycji.", "products_suggestNoResults": "Brak propozycji.",
"products_noProducts": "Nie znaleziono produktów.", "products_noProducts": "Nie znaleziono produktów.",
"products_filterAll": "Wszystkie", "products_filterAll": "Wszystkie",
"products_filterOwned": "Posiadane", "products_filterOwned": "Posiadane",
"products_filterUnowned": "Nieposiadane", "products_filterUnowned": "Nieposiadane",
"products_colName": "Nazwa", "products_colName": "Nazwa",
"products_colBrand": "Marka", "products_colBrand": "Marka",
"products_colTargets": "Cele", "products_colTargets": "Cele",
"products_colTime": "Pora", "products_colTime": "Pora",
"products_newTitle": "Nowy produkt", "products_newTitle": "Nowy produkt",
"products_backToList": "← Produkty", "products_backToList": "← Produkty",
"products_createProduct": "Utwórz produkt", "products_createProduct": "Utwórz produkt",
"products_saveChanges": "Zapisz zmiany", "products_saveChanges": "Zapisz zmiany",
"products_deleteProduct": "Usuń produkt", "products_deleteProduct": "Usuń produkt",
"products_confirmDelete": "Usunąć ten produkt?", "products_confirmDelete": "Usunąć ten produkt?",
"products_noInventory": "Brak opakowań w magazynie.", "products_noInventory": "Brak opakowań w magazynie.",
"inventory_title": "Opakowania ({count})", "inventory_title": "Opakowania ({count})",
"inventory_addPackage": "+ Dodaj opakowanie", "inventory_addPackage": "+ Dodaj opakowanie",
"inventory_packageAdded": "Opakowanie dodane.", "inventory_packageAdded": "Opakowanie dodane.",
"inventory_packageUpdated": "Opakowanie zaktualizowane.", "inventory_packageUpdated": "Opakowanie zaktualizowane.",
"inventory_packageDeleted": "Opakowanie usunięte.", "inventory_packageDeleted": "Opakowanie usunięte.",
"inventory_alreadyOpened": "Już otwarte", "inventory_alreadyOpened": "Już otwarte",
"inventory_openedDate": "Data otwarcia", "inventory_openedDate": "Data otwarcia",
"inventory_finishedDate": "Data skończenia", "inventory_finishedDate": "Data skończenia",
"inventory_expiryDate": "Data ważności", "inventory_expiryDate": "Data ważności",
"inventory_currentWeight": "Aktualna waga (g)", "inventory_currentWeight": "Aktualna waga (g)",
"inventory_lastWeighed": "Ostatnie ważenie", "inventory_lastWeighed": "Ostatnie ważenie",
"inventory_notes": "Notatki", "inventory_notes": "Notatki",
"inventory_badgeOpen": "Otwarte", "inventory_badgeOpen": "Otwarte",
"inventory_badgeSealed": "Zamknięte", "inventory_badgeSealed": "Zamknięte",
"inventory_badgeFinished": "Skończone", "inventory_badgeFinished": "Skończone",
"inventory_exp": "Wazność:", "inventory_exp": "Wazność:",
"inventory_opened": "Otwarto:", "inventory_opened": "Otwarto:",
"inventory_finished": "Skończono:", "inventory_finished": "Skończono:",
"inventory_remaining": "g pozostało", "inventory_remaining": "g pozostało",
"inventory_weighed": "Ważono:", "inventory_weighed": "Ważono:",
"inventory_confirmDelete": "Usunąć to opakowanie?", "inventory_confirmDelete": "Usunąć to opakowanie?",
"routines_title": "Rutyny", "routines_title": "Rutyny",
"routines_count": "{count} rutyno (ostatnie 30 dni)", "routines_count": "{count} rutyno (ostatnie 30 dni)",
"routines_suggestAI": "Zaproponuj rutynę AI", "routines_suggestAI": "Zaproponuj rutynę AI",
"routines_addNew": "+ Nowa rutyna", "routines_addNew": "+ Nowa rutyna",
"routines_noRoutines": "Nie znaleziono rutyno.", "routines_noRoutines": "Nie znaleziono rutyno.",
"routines_newTitle": "Nowa rutyna", "routines_newTitle": "Nowa rutyna",
"routines_backToList": "← Rutyny", "routines_backToList": "← Rutyny",
"routines_detailsTitle": "Szczegóły rutyny", "routines_detailsTitle": "Szczegóły rutyny",
"routines_date": "Data *", "routines_date": "Data *",
"routines_amOrPm": "AM lub PM *", "routines_amOrPm": "AM lub PM *",
"routines_notes": "Notatki", "routines_notes": "Notatki",
"routines_notesPlaceholder": "Opcjonalne notatki", "routines_notesPlaceholder": "Opcjonalne notatki",
"routines_createRoutine": "Utwórz rutynę", "routines_createRoutine": "Utwórz rutynę",
"routines_deleteRoutine": "Usuń rutynę", "routines_deleteRoutine": "Usuń rutynę",
"routines_confirmDelete": "Usunąć tę rutynę?", "routines_confirmDelete": "Usunąć tę rutynę?",
"routines_steps": "Kroki ({count})", "routines_steps": "Kroki ({count})",
"routines_addStep": "+ Dodaj krok", "routines_addStep": "+ Dodaj krok",
"routines_addStepTitle": "Dodaj krok", "routines_addStepTitle": "Dodaj krok",
"routines_product": "Produkt", "routines_product": "Produkt",
"routines_selectProduct": "Wybierz produkt", "routines_selectProduct": "Wybierz produkt",
"routines_dose": "Dawka", "routines_dose": "Dawka",
"routines_dosePlaceholder": "np. 2 pompki", "routines_dosePlaceholder": "np. 2 pompki",
"routines_region": "Okolica", "routines_region": "Okolica",
"routines_regionPlaceholder": "np. twarz", "routines_regionPlaceholder": "np. twarz",
"routines_addStepBtn": "Dodaj krok", "routines_addStepBtn": "Dodaj krok",
"routines_unknownStep": "Nieznany krok", "routines_unknownStep": "Nieznany krok",
"routines_noSteps": "Brak kroków.", "routines_noSteps": "Brak kroków.",
"grooming_title": "Harmonogram pielęgnacji", "grooming_title": "Harmonogram pielęgnacji",
"grooming_backToRoutines": "← Rutyny", "grooming_backToRoutines": "← Rutyny",
"grooming_addEntry": "+ Dodaj wpis", "grooming_addEntry": "+ Dodaj wpis",
"grooming_entryAdded": "Wpis dodany.", "grooming_entryAdded": "Wpis dodany.",
"grooming_entryUpdated": "Wpis zaktualizowany.", "grooming_entryUpdated": "Wpis zaktualizowany.",
"grooming_entryDeleted": "Wpis usunięty.", "grooming_entryDeleted": "Wpis usunięty.",
"grooming_dayOfWeek": "Dzień tygodnia", "grooming_dayOfWeek": "Dzień tygodnia",
"grooming_action": "Czynność", "grooming_action": "Czynność",
"grooming_notesOptional": "Notatki (opcjonalnie)", "grooming_notesOptional": "Notatki (opcjonalnie)",
"grooming_notesPlaceholder": "np. co 2 tygodnie", "grooming_notesPlaceholder": "np. co 2 tygodnie",
"grooming_noEntries": "Brak wpisów. Kliknij \"+ Dodaj wpis\", aby zacząć.", "grooming_noEntries": "Brak wpisów. Kliknij \"+ Dodaj wpis\", aby zacząć.",
"grooming_confirmDelete": "Usunąć ten wpis?", "grooming_confirmDelete": "Usunąć ten wpis?",
"grooming_actionShavingRazor": "Golenie maszynką", "grooming_actionShavingRazor": "Golenie maszynką",
"grooming_actionShavingOneblade": "Golenie OneBlade", "grooming_actionShavingOneblade": "Golenie OneBlade",
"grooming_actionDermarolling": "Dermarolling", "grooming_actionDermarolling": "Dermarolling",
"grooming_dayMonday": "Poniedziałek", "grooming_dayMonday": "Poniedziałek",
"grooming_dayTuesday": "Wtorek", "grooming_dayTuesday": "Wtorek",
"grooming_dayWednesday": "Środa", "grooming_dayWednesday": "Środa",
"grooming_dayThursday": "Czwartek", "grooming_dayThursday": "Czwartek",
"grooming_dayFriday": "Piątek", "grooming_dayFriday": "Piątek",
"grooming_daySaturday": "Sobota", "grooming_daySaturday": "Sobota",
"grooming_daySunday": "Niedziela", "grooming_daySunday": "Niedziela",
"suggest_title": "Propozycja rutyny AI", "suggest_title": "Propozycja rutyny AI",
"suggest_backToRoutines": "← Rutyny", "suggest_backToRoutines": "← Rutyny",
"suggest_singleTab": "Jedna rutyna", "suggest_singleTab": "Jedna rutyna",
"suggest_batchTab": "Batch / Urlop", "suggest_batchTab": "Batch / Urlop",
"suggest_singleParams": "Parametry", "suggest_singleParams": "Parametry",
"suggest_date": "Data", "suggest_date": "Data",
"suggest_timeOfDay": "Pora dnia", "suggest_timeOfDay": "Pora dnia",
"suggest_contextLabel": "Dodatkowy kontekst dla AI", "suggest_contextLabel": "Dodatkowy kontekst dla AI",
"suggest_contextOptional": "(opcjonalny)", "suggest_contextOptional": "(opcjonalny)",
"suggest_contextPlaceholder": "np. wieczór imprezowy, skupiam się na nawilżeniu...", "suggest_contextPlaceholder": "np. wieczór imprezowy, skupiam się na nawilżeniu...",
"suggest_leavingHomeLabel": "Wychodzę dziś z domu", "suggest_leavingHomeLabel": "Wychodzę dziś z domu",
"suggest_leavingHomeHint": "Wpływa na wybór SPF — zaznaczone: SPF50+, odznaczone: SPF30.", "suggest_leavingHomeHint": "Wpływa na wybór SPF — zaznaczone: SPF50+, odznaczone: SPF30.",
"suggest_minoxidilToggleLabel": "Priorytet: gęstość brody/wąsów (minoksydyl)", "suggest_minoxidilToggleLabel": "Priorytet: gęstość brody/wąsów (minoksydyl)",
"suggest_minoxidilToggleHint": "Po włączeniu AI jawnie uwzględni minoksydyl dla obszaru brody/wąsów, jeśli jest dostępny.", "suggest_minoxidilToggleHint": "Po włączeniu AI jawnie uwzględni minoksydyl dla obszaru brody/wąsów, jeśli jest dostępny.",
"suggest_generateBtn": "Generuj propozycję", "suggest_generateBtn": "Generuj propozycję",
"suggest_generating": "Generuję…", "suggest_generating": "Generuję…",
"suggest_proposalTitle": "Propozycja", "suggest_proposalTitle": "Propozycja",
"suggest_saveRoutine": "Zapisz rutynę", "suggest_saveRoutine": "Zapisz rutynę",
"suggest_saving": "Zapisuję…", "suggest_saving": "Zapisuję…",
"suggest_regenerate": "Wygeneruj ponownie", "suggest_regenerate": "Wygeneruj ponownie",
"suggest_batchRange": "Zakres dat", "suggest_batchRange": "Zakres dat",
"suggest_fromDate": "Od", "suggest_fromDate": "Od",
"suggest_toDate": "Do (max 14 dni)", "suggest_toDate": "Do (max 14 dni)",
"suggest_batchContextLabel": "Kontekst / cel wyjazdu", "suggest_batchContextLabel": "Kontekst / cel wyjazdu",
"suggest_batchContextPlaceholder": "np. słoneczna podróż do Włoch, aktywny urlop górski...", "suggest_batchContextPlaceholder": "np. słoneczna podróż do Włoch, aktywny urlop górski...",
"suggest_generatePlan": "Generuj plan", "suggest_generatePlan": "Generuj plan",
"suggest_generatingPlan": "Generuję plan…", "suggest_generatingPlan": "Generuję plan…",
"suggest_planTitle": "Plan ({count} dni)", "suggest_planTitle": "Plan ({count} dni)",
"suggest_saveAllRoutines": "Zapisz wszystkie rutyny", "suggest_saveAllRoutines": "Zapisz wszystkie rutyny",
"suggest_amSteps": "kroków", "suggest_amSteps": "kroków",
"suggest_pmSteps": "kroków", "suggest_pmSteps": "kroków",
"suggest_noAmSteps": "Brak kroków AM.", "suggest_noAmSteps": "Brak kroków AM.",
"suggest_noPmSteps": "Brak kroków PM.", "suggest_noPmSteps": "Brak kroków PM.",
"suggest_errorDefault": "Błąd podczas generowania.", "suggest_errorDefault": "Błąd podczas generowania.",
"suggest_errorBatch": "Błąd podczas generowania planu.", "suggest_errorBatch": "Błąd podczas generowania planu.",
"suggest_errorSave": "Błąd podczas zapisywania.", "suggest_errorSave": "Błąd podczas zapisywania.",
"suggest_amMorning": "AM (rano)", "suggest_amMorning": "AM (rano)",
"suggest_pmEvening": "PM (wieczór)", "suggest_pmEvening": "PM (wieczór)",
"medications_title": "Leki", "medications_title": "Leki",
"medications_count": "{count} wpisów", "medications_count": "{count} wpisów",
"medications_addNew": "+ Dodaj lek", "medications_addNew": "+ Dodaj lek",
"medications_newTitle": "Nowy lek", "medications_newTitle": "Nowy lek",
"medications_kind": "Rodzaj", "medications_kind": "Rodzaj",
"medications_productName": "Nazwa produktu *", "medications_productName": "Nazwa produktu *",
"medications_productNamePlaceholder": "np. Witamina D3", "medications_productNamePlaceholder": "np. Witamina D3",
"medications_activeSubstance": "Substancja czynna", "medications_activeSubstance": "Substancja czynna",
"medications_activeSubstancePlaceholder": "np. cholekalcyferol", "medications_activeSubstancePlaceholder": "np. cholekalcyferol",
"medications_notes": "Notatki", "medications_notes": "Notatki",
"medications_added": "Lek dodany.", "medications_added": "Lek dodany.",
"medications_usages": "{count} użyć", "medications_usages": "{count} użyć",
"medications_noMedications": "Brak leków.", "medications_noMedications": "Brak leków.",
"medications_kindPrescription": "Na receptę", "medications_kindPrescription": "Na receptę",
"medications_kindOtc": "OTC (bez recepty)", "medications_kindOtc": "OTC (bez recepty)",
"medications_kindSupplement": "Suplement", "medications_kindSupplement": "Suplement",
"medications_kindHerbal": "Zioła", "medications_kindHerbal": "Zioła",
"medications_kindOther": "Inne", "medications_kindOther": "Inne",
"labResults_title": "Wyniki badań", "labResults_title": "Wyniki badań",
"labResults_count": "{count} wyników", "labResults_count": "{count} wyników",
"labResults_addNew": "+ Dodaj wynik", "labResults_addNew": "+ Dodaj wynik",
"labResults_newTitle": "Nowy wynik badania", "labResults_newTitle": "Nowy wynik badania",
"labResults_flagFilter": "Flaga:", "labResults_flagFilter": "Flaga:",
"labResults_flagAll": "Wszystkie", "labResults_flagAll": "Wszystkie",
"labResults_flagNone": "Brak", "labResults_flagNone": "Brak",
"labResults_date": "Data *", "labResults_date": "Data *",
"labResults_loincCode": "Kod LOINC *", "labResults_loincCode": "Kod LOINC *",
"labResults_testName": "Nazwa badania", "labResults_testName": "Nazwa badania",
"labResults_testNamePlaceholder": "np. Hemoglobina", "labResults_testNamePlaceholder": "np. Hemoglobina",
"labResults_lab": "Laboratorium", "labResults_lab": "Laboratorium",
"labResults_labPlaceholder": "np. LabCorp", "labResults_labPlaceholder": "np. LabCorp",
"labResults_value": "Wartość", "labResults_value": "Wartość",
"labResults_unit": "Jednostka", "labResults_unit": "Jednostka",
"labResults_unitPlaceholder": "np. g/dL", "labResults_unitPlaceholder": "np. g/dL",
"labResults_flag": "Flaga", "labResults_flag": "Flaga",
"labResults_added": "Wynik dodany.", "labResults_added": "Wynik dodany.",
"labResults_colDate": "Data", "labResults_colDate": "Data",
"labResults_colTest": "Badanie", "labResults_colTest": "Badanie",
"labResults_colLoinc": "LOINC", "labResults_colLoinc": "LOINC",
"labResults_colValue": "Wartość", "labResults_colValue": "Wartość",
"labResults_colFlag": "Flaga", "labResults_colFlag": "Flaga",
"labResults_colLab": "Lab", "labResults_colLab": "Lab",
"labResults_noResults": "Nie znaleziono wyników badań.", "labResults_noResults": "Nie znaleziono wyników badań.",
"skin_title": "Stan skóry", "skin_title": "Stan skóry",
"skin_count": "{count} wpisów", "skin_count": "{count} wpisów",
"skin_addNew": "+ Dodaj wpis", "skin_addNew": "+ Dodaj wpis",
"skin_aiAnalysisTitle": "Analiza AI ze zdjęć", "skin_aiAnalysisTitle": "Analiza AI ze zdjęć",
"skin_aiUploadText": "Prześlij 13 zdjęcia skóry. AI wypełni pola formularza poniżej.", "skin_aiUploadText": "Prześlij 13 zdjęcia skóry. AI wypełni pola formularza poniżej.",
"skin_analyzePhotos": "Analizuj zdjęcia", "skin_analyzePhotos": "Analizuj zdjęcia",
"skin_analyzing": "Analizuję…", "skin_analyzing": "Analizuję…",
"skin_newSnapshotTitle": "Nowy wpis", "skin_newSnapshotTitle": "Nowy wpis",
"skin_date": "Data *", "skin_date": "Data *",
"skin_overallState": "Ogólny stan", "skin_overallState": "Ogólny stan",
"skin_texture": "Tekstura", "skin_texture": "Tekstura",
"skin_skinType": "Typ skóry", "skin_skinType": "Typ skóry",
"skin_barrierState": "Stan bariery", "skin_barrierState": "Stan bariery",
"skin_hydration": "Nawilżenie (15)", "skin_hydration": "Nawilżenie (15)",
"skin_sensitivity": "Wrażliwość (15)", "skin_sensitivity": "Wrażliwość (15)",
"skin_sebumTzone": "Sebum T-zone (15)", "skin_sebumTzone": "Sebum T-zone (15)",
"skin_sebumCheeks": "Sebum policzki (15)", "skin_sebumCheeks": "Sebum policzki (15)",
"skin_activeConcerns": "Aktywne problemy (przecinek)", "skin_activeConcerns": "Aktywne problemy (przecinek)",
"skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie", "skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie",
"skin_priorities": "Priorytety (przecinek)", "skin_priorities": "Priorytety (przecinek)",
"skin_prioritiesPlaceholder": "wzmocnić barierę, redukować zaczerwienienie", "skin_prioritiesPlaceholder": "wzmocnić barierę, redukować zaczerwienienie",
"skin_prioritiesLabel": "Priorytety", "skin_prioritiesLabel": "Priorytety",
"skin_notes": "Notatki", "skin_notes": "Notatki",
"skin_addSnapshot": "Dodaj wpis", "skin_addSnapshot": "Dodaj wpis",
"skin_snapshotAdded": "Wpis dodany.", "skin_snapshotAdded": "Wpis dodany.",
"skin_snapshotUpdated": "Wpis zaktualizowany.", "skin_snapshotUpdated": "Wpis zaktualizowany.",
"skin_snapshotDeleted": "Wpis usunięty.", "skin_snapshotDeleted": "Wpis usunięty.",
"skin_noSnapshots": "Brak wpisów o stanie skóry.", "skin_noSnapshots": "Brak wpisów o stanie skóry.",
"skin_hydrationLabel": "Nawilżenie", "skin_hydrationLabel": "Nawilżenie",
"skin_sensitivityLabel": "Wrażliwość", "skin_sensitivityLabel": "Wrażliwość",
"skin_barrierLabel": "Bariera", "skin_barrierLabel": "Bariera",
"skin_stateExcellent": "doskonały", "skin_stateExcellent": "doskonały",
"skin_stateGood": "dobry", "skin_stateGood": "dobry",
"skin_stateFair": "przeciętny", "skin_stateFair": "przeciętny",
"skin_statePoor": "zły", "skin_statePoor": "zły",
"skin_textureSmooth": "gładka", "skin_textureSmooth": "gładka",
"skin_textureRough": "szorstka", "skin_textureRough": "szorstka",
"skin_textureFlaky": "łuszcząca się", "skin_textureFlaky": "łuszcząca się",
"skin_textureBumpy": "nierówna", "skin_textureBumpy": "nierówna",
"skin_barrierIntact": "nienaruszona", "skin_barrierIntact": "nienaruszona",
"skin_barrierMildly": "lekko naruszona", "skin_barrierMildly": "lekko naruszona",
"skin_barrierCompromised": "naruszona", "skin_barrierCompromised": "naruszona",
"skin_typeDry": "sucha", "skin_typeDry": "sucha",
"skin_typeOily": "tłusta", "skin_typeOily": "tłusta",
"skin_typeCombination": "mieszana", "skin_typeCombination": "mieszana",
"skin_typeSensitive": "wrażliwa", "skin_typeSensitive": "wrażliwa",
"skin_typeNormal": "normalna", "skin_typeNormal": "normalna",
"skin_typeAcneProne": "trądzikowa", "skin_typeAcneProne": "trądzikowa",
"productForm_aiPrefill": "Uzupełnienie AI", "productForm_aiPrefill": "Uzupełnienie AI",
"productForm_aiPrefillText": "Wklej opis produktu ze strony, listę składników lub inny tekst. AI uzupełni dostępne pola — możesz je przejrzeć i poprawić przed zapisem.", "productForm_aiPrefillText": "Wklej opis produktu ze strony, listę składników lub inny tekst. AI uzupełni dostępne pola — możesz je przejrzeć i poprawić przed zapisem.",
"productForm_pasteText": "Wklej tutaj opis produktu, składniki INCI...", "productForm_pasteText": "Wklej tutaj opis produktu, składniki INCI...",
"productForm_parseWithAI": "Uzupełnij pola (AI)", "productForm_parseWithAI": "Uzupełnij pola (AI)",
"productForm_parsing": "Przetwarzam…", "productForm_parsing": "Przetwarzam…",
"productForm_basicInfo": "Informacje podstawowe", "productForm_basicInfo": "Informacje podstawowe",
"productForm_name": "Nazwa *", "productForm_name": "Nazwa *",
"productForm_namePlaceholder": "np. Hydro Boost Water Gel", "productForm_namePlaceholder": "np. Hydro Boost Water Gel",
"productForm_brand": "Marka *", "productForm_brand": "Marka *",
"productForm_brandPlaceholder": "np. Neutrogena", "productForm_brandPlaceholder": "np. Neutrogena",
"productForm_lineName": "Linia / seria", "productForm_lineName": "Linia / seria",
"productForm_lineNamePlaceholder": "np. Hydro Boost", "productForm_lineNamePlaceholder": "np. Hydro Boost",
"productForm_url": "URL", "productForm_url": "URL",
"productForm_sku": "SKU", "productForm_sku": "SKU",
"productForm_skuPlaceholder": "np. NTR-HB-50", "productForm_skuPlaceholder": "np. NTR-HB-50",
"productForm_barcode": "Kod kreskowy / EAN", "productForm_barcode": "Kod kreskowy / EAN",
"productForm_barcodePlaceholder": "np. 3614273258975", "productForm_barcodePlaceholder": "np. 3614273258975",
"productForm_classification": "Klasyfikacja", "productForm_classification": "Klasyfikacja",
"productForm_category": "Kategoria *", "productForm_category": "Kategoria *",
"productForm_selectCategory": "Wybierz kategorię", "productForm_selectCategory": "Wybierz kategorię",
"productForm_time": "Pora *", "productForm_time": "Pora *",
"productForm_timeOptions": "AM / PM / Oba", "productForm_timeOptions": "AM / PM / Oba",
"productForm_timeBoth": "Oba", "productForm_timeBoth": "Oba",
"productForm_leaveOn": "Leave-on *", "productForm_leaveOn": "Leave-on *",
"productForm_leaveOnYes": "Tak (leave-on)", "productForm_leaveOnYes": "Tak (leave-on)",
"productForm_leaveOnNo": "Nie (rinse-off)", "productForm_leaveOnNo": "Nie (rinse-off)",
"productForm_texture": "Tekstura", "productForm_texture": "Tekstura",
"productForm_selectTexture": "Wybierz teksturę", "productForm_selectTexture": "Wybierz teksturę",
"productForm_absorptionSpeed": "Szybkość wchłaniania", "productForm_absorptionSpeed": "Szybkość wchłaniania",
"productForm_selectSpeed": "Wybierz szybkość", "productForm_selectSpeed": "Wybierz szybkość",
"productForm_skinProfile": "Profil skóry", "productForm_skinProfile": "Profil skóry",
"productForm_recommendedFor": "Polecane dla typów skóry", "productForm_recommendedFor": "Polecane dla typów skóry",
"productForm_targetConcerns": "Problemy docelowe", "productForm_targetConcerns": "Problemy docelowe",
"productForm_contraindications": "Przeciwwskazania (jedno na linię)", "productForm_contraindications": "Przeciwwskazania (jedno na linię)",
"productForm_contraindicationsPlaceholder": "np. aktywna rosacea", "productForm_contraindicationsPlaceholder": "np. aktywna rosacea",
"productForm_ingredients": "Składniki", "productForm_ingredients": "Składniki",
"productForm_inciList": "Lista INCI (jeden składnik na linię)", "productForm_inciList": "Lista INCI (jeden składnik na linię)",
"productForm_activeIngredients": "Składniki aktywne", "productForm_activeIngredients": "Składniki aktywne",
"productForm_addActive": "+ Dodaj aktywny", "productForm_addActive": "+ Dodaj aktywny",
"productForm_noActives": "Brak składników aktywnych.", "productForm_noActives": "Brak składników aktywnych.",
"productForm_activeName": "Nazwa", "productForm_activeName": "Nazwa",
"productForm_activePercent": "%", "productForm_activePercent": "%",
"productForm_activeStrength": "Siła", "productForm_activeStrength": "Siła",
"productForm_activeIrritation": "Podrażnienie", "productForm_activeIrritation": "Podrażnienie",
"productForm_activeFunctions": "Funkcje", "productForm_activeFunctions": "Funkcje",
"productForm_effectProfile": "Profil działania (05)", "productForm_effectProfile": "Profil działania (05)",
"productForm_interactions": "Interakcje", "productForm_interactions": "Interakcje",
"productForm_synergizesWith": "Synergizuje z (jedno na linię)", "productForm_synergizesWith": "Synergizuje z (jedno na linię)",
"productForm_incompatibleWith": "Niekompatybilny z", "productForm_incompatibleWith": "Niekompatybilny z",
"productForm_addIncompatibility": "+ Dodaj niekompatybilność", "productForm_addIncompatibility": "+ Dodaj niekompatybilność",
"productForm_noIncompatibilities": "Brak niekompatybilności.", "productForm_noIncompatibilities": "Brak niekompatybilności.",
"productForm_incompTarget": "Składnik docelowy", "productForm_incompTarget": "Składnik docelowy",
"productForm_incompScope": "Zakres", "productForm_incompScope": "Zakres",
"productForm_incompReason": "Powód (opcjonalny)", "productForm_incompReason": "Powód (opcjonalny)",
"productForm_incompReasonPlaceholder": "np. zmniejsza skuteczność", "productForm_incompReasonPlaceholder": "np. zmniejsza skuteczność",
"productForm_incompScopeSelect": "Wybierz…", "productForm_incompScopeSelect": "Wybierz…",
"productForm_contextRules": "Reguły kontekstu", "productForm_contextRules": "Reguły kontekstu",
"productForm_ctxAfterShaving": "Bezpieczny po goleniu", "productForm_ctxAfterShaving": "Bezpieczny po goleniu",
"productForm_ctxAfterAcids": "Bezpieczny po kwasach", "productForm_ctxAfterAcids": "Bezpieczny po kwasach",
"productForm_ctxAfterRetinoids": "Bezpieczny po retinoidach", "productForm_ctxAfterRetinoids": "Bezpieczny po retinoidach",
"productForm_ctxCompromisedBarrier": "Bezpieczny przy naruszonej barierze", "productForm_ctxCompromisedBarrier": "Bezpieczny przy naruszonej barierze",
"productForm_ctxLowUvOnly": "Tylko przy niskim UV (wieczór/zakrycie)", "productForm_ctxLowUvOnly": "Tylko przy niskim UV (wieczór/zakrycie)",
"productForm_productDetails": "Szczegóły produktu", "productForm_productDetails": "Szczegóły produktu",
"productForm_priceTier": "Przedział cenowy", "productForm_priceTier": "Przedział cenowy",
"productForm_selectTier": "Wybierz przedział", "productForm_selectTier": "Wybierz przedział",
"productForm_sizeMl": "Rozmiar (ml)", "productForm_sizeMl": "Rozmiar (ml)",
"productForm_fullWeightG": "Waga pełna (g)", "productForm_fullWeightG": "Waga pełna (g)",
"productForm_emptyWeightG": "Waga pustego (g)", "productForm_emptyWeightG": "Waga pustego (g)",
"productForm_paoMonths": "PAO (miesiące)", "productForm_paoMonths": "PAO (miesiące)",
"productForm_phMin": "pH min", "productForm_phMin": "pH min",
"productForm_phMax": "pH max", "productForm_phMax": "pH max",
"productForm_usageNotes": "Notatki o stosowaniu", "productForm_usageNotes": "Notatki o stosowaniu",
"productForm_usageNotesPlaceholder": "np. Nakładaj na wilgotną skórę, unikaj okolic oczu", "productForm_usageNotesPlaceholder": "np. Nakładaj na wilgotną skórę, unikaj okolic oczu",
"productForm_safetyFlags": "Flagi bezpieczeństwa", "productForm_safetyFlags": "Flagi bezpieczeństwa",
"productForm_fragranceFree": "Bez zapachów", "productForm_fragranceFree": "Bez zapachów",
"productForm_essentialOilsFree": "Bez olejków eterycznych", "productForm_essentialOilsFree": "Bez olejków eterycznych",
"productForm_alcoholDenatFree": "Bez alkoholu denat.", "productForm_alcoholDenatFree": "Bez alkoholu denat.",
"productForm_pregnancySafe": "Bezpieczny w ciąży", "productForm_pregnancySafe": "Bezpieczny w ciąży",
"productForm_usageConstraints": "Ograniczenia stosowania", "productForm_usageConstraints": "Ograniczenia stosowania",
"productForm_minIntervalHours": "Min. przerwa (godziny)", "productForm_minIntervalHours": "Min. przerwa (godziny)",
"productForm_maxFrequencyPerWeek": "Max użyć na tydzień", "productForm_maxFrequencyPerWeek": "Max użyć na tydzień",
"productForm_isMedication": "To lek", "productForm_isMedication": "To lek",
"productForm_isTool": "To narzędzie (np. dermaroller)", "productForm_isTool": "To narzędzie (np. dermaroller)",
"productForm_needleLengthMm": "Długość igły (mm, tylko narzędzia)", "productForm_needleLengthMm": "Długość igły (mm, tylko narzędzia)",
"productForm_personalNotes": "Notatki osobiste", "productForm_personalNotes": "Notatki osobiste",
"productForm_repurchaseIntent": "Zamiar ponownego zakupu", "productForm_repurchaseIntent": "Zamiar ponownego zakupu",
"productForm_toleranceNotes": "Notatki o tolerancji", "productForm_toleranceNotes": "Notatki o tolerancji",
"productForm_toleranceNotesPlaceholder": "np. Lekkie pieczenie, ustępuje po 2 tygodniach", "productForm_toleranceNotesPlaceholder": "np. Lekkie pieczenie, ustępuje po 2 tygodniach",
"productForm_categoryCleanser": "Żel/pianka do mycia", "productForm_categoryCleanser": "Żel/pianka do mycia",
"productForm_categoryToner": "Tonik", "productForm_categoryToner": "Tonik",
"productForm_categoryEssence": "Esencja", "productForm_categoryEssence": "Esencja",
"productForm_categorySerum": "Serum", "productForm_categorySerum": "Serum",
"productForm_categoryMoisturizer": "Krem", "productForm_categoryMoisturizer": "Krem",
"productForm_categorySpf": "SPF", "productForm_categorySpf": "SPF",
"productForm_categoryMask": "Maska", "productForm_categoryMask": "Maska",
"productForm_categoryExfoliant": "Peeling", "productForm_categoryExfoliant": "Peeling",
"productForm_categoryHairTreatment": "Pielęgnacja włosów", "productForm_categoryHairTreatment": "Pielęgnacja włosów",
"productForm_categoryTool": "Narzędzie", "productForm_categoryTool": "Narzędzie",
"productForm_categorySpotTreatment": "Punkt leczenia", "productForm_categorySpotTreatment": "Punkt leczenia",
"productForm_categoryOil": "Olejek", "productForm_categoryOil": "Olejek",
"productForm_textureWatery": "Wodnista", "productForm_textureWatery": "Wodnista",
"productForm_textureGel": "Żel", "productForm_textureGel": "Żel",
"productForm_textureEmulsion": "Emulsja", "productForm_textureEmulsion": "Emulsja",
"productForm_textureCream": "Krem", "productForm_textureCream": "Krem",
"productForm_textureOil": "Olejek", "productForm_textureOil": "Olejek",
"productForm_textureBalm": "Balsam", "productForm_textureBalm": "Balsam",
"productForm_textureFoam": "Pianka", "productForm_textureFoam": "Pianka",
"productForm_textureFluid": "Fluid", "productForm_textureFluid": "Fluid",
"productForm_absorptionVeryFast": "Bardzo szybkie", "productForm_absorptionVeryFast": "Bardzo szybkie",
"productForm_absorptionFast": "Szybkie", "productForm_absorptionFast": "Szybkie",
"productForm_absorptionModerate": "Umiarkowane", "productForm_absorptionModerate": "Umiarkowane",
"productForm_absorptionSlow": "Wolne", "productForm_absorptionSlow": "Wolne",
"productForm_absorptionVerySlow": "Bardzo wolne", "productForm_absorptionVerySlow": "Bardzo wolne",
"productForm_priceBudget": "Budżetowy", "productForm_priceBudget": "Budżetowy",
"productForm_priceMid": "Średni", "productForm_priceMid": "Średni",
"productForm_pricePremium": "Premium", "productForm_pricePremium": "Premium",
"productForm_priceLuxury": "Luksusowy", "productForm_priceLuxury": "Luksusowy",
"productForm_skinTypeDry": "sucha", "productForm_skinTypeDry": "sucha",
"productForm_skinTypeOily": "tłusta", "productForm_skinTypeOily": "tłusta",
"productForm_skinTypeCombination": "mieszana", "productForm_skinTypeCombination": "mieszana",
"productForm_skinTypeSensitive": "wrażliwa", "productForm_skinTypeSensitive": "wrażliwa",
"productForm_skinTypeNormal": "normalna", "productForm_skinTypeNormal": "normalna",
"productForm_skinTypeAcneProne": "trądzikowa", "productForm_skinTypeAcneProne": "trądzikowa",
"productForm_concernAcne": "trądzik", "productForm_concernAcne": "trądzik",
"productForm_concernRosacea": "rosacea", "productForm_concernRosacea": "rosacea",
"productForm_concernHyperpigmentation": "przebarwienia", "productForm_concernHyperpigmentation": "przebarwienia",
"productForm_concernAging": "starzenie", "productForm_concernAging": "starzenie",
"productForm_concernDehydration": "odwodnienie", "productForm_concernDehydration": "odwodnienie",
"productForm_concernRedness": "zaczerwienienie", "productForm_concernRedness": "zaczerwienienie",
"productForm_concernDamagedBarrier": "naruszona bariera", "productForm_concernDamagedBarrier": "naruszona bariera",
"productForm_concernPoreVisibility": "widoczność porów", "productForm_concernPoreVisibility": "widoczność porów",
"productForm_concernUnevenTexture": "nierówna tekstura", "productForm_concernUnevenTexture": "nierówna tekstura",
"productForm_concernHairGrowth": "wzrost włosów", "productForm_concernHairGrowth": "wzrost włosów",
"productForm_concernSebumExcess": "nadmiar sebum", "productForm_concernSebumExcess": "nadmiar sebum",
"productForm_fnHumectant": "humektant", "productForm_fnHumectant": "humektant",
"productForm_fnEmollient": "emolient", "productForm_fnEmollient": "emolient",
"productForm_fnOcclusive": "okluzja", "productForm_fnOcclusive": "okluzja",
"productForm_fnExfoliantAha": "peeling AHA", "productForm_fnExfoliantAha": "peeling AHA",
"productForm_fnExfoliantBha": "peeling BHA", "productForm_fnExfoliantBha": "peeling BHA",
"productForm_fnExfoliantPha": "peeling PHA", "productForm_fnExfoliantPha": "peeling PHA",
"productForm_fnRetinoid": "retinoid", "productForm_fnRetinoid": "retinoid",
"productForm_fnAntioxidant": "antyoksydant", "productForm_fnAntioxidant": "antyoksydant",
"productForm_fnSoothing": "łagodzący", "productForm_fnSoothing": "łagodzący",
"productForm_fnBarrierSupport": "wsparcie bariery", "productForm_fnBarrierSupport": "wsparcie bariery",
"productForm_fnBrightening": "rozjaśniający", "productForm_fnBrightening": "rozjaśniający",
"productForm_fnAntiAcne": "przeciwtrądzikowy", "productForm_fnAntiAcne": "przeciwtrądzikowy",
"productForm_fnCeramide": "ceramid", "productForm_fnCeramide": "ceramid",
"productForm_fnNiacinamide": "niacynamid", "productForm_fnNiacinamide": "niacynamid",
"productForm_fnSunscreen": "filtr UV", "productForm_fnSunscreen": "filtr UV",
"productForm_fnPeptide": "peptyd", "productForm_fnPeptide": "peptyd",
"productForm_fnHairGrowth": "stymulator wzrostu włosów", "productForm_fnHairGrowth": "stymulator wzrostu włosów",
"productForm_fnPrebiotic": "prebiotyk", "productForm_fnPrebiotic": "prebiotyk",
"productForm_fnVitaminC": "witamina C", "productForm_fnVitaminC": "witamina C",
"productForm_fnAntiAging": "przeciwstarzeniowy", "productForm_fnAntiAging": "przeciwstarzeniowy",
"productForm_scopeSameStep": "ten sam krok", "productForm_scopeSameStep": "ten sam krok",
"productForm_scopeSameDay": "ten sam dzień", "productForm_scopeSameDay": "ten sam dzień",
"productForm_scopeSamePeriod": "ten sam okres", "productForm_scopeSamePeriod": "ten sam okres",
"productForm_strengthLow": "1 Niskie", "productForm_strengthLow": "1 Niskie",
"productForm_strengthMedium": "2 Średnie", "productForm_strengthMedium": "2 Średnie",
"productForm_strengthHigh": "3 Wysokie", "productForm_strengthHigh": "3 Wysokie",
"productForm_effectHydrationImmediate": "Nawilżenie (natychmiastowe)", "productForm_effectHydrationImmediate": "Nawilżenie (natychmiastowe)",
"productForm_effectHydrationLongTerm": "Nawilżenie (długoterminowe)", "productForm_effectHydrationLongTerm": "Nawilżenie (długoterminowe)",
"productForm_effectBarrierRepair": "Naprawa bariery", "productForm_effectBarrierRepair": "Naprawa bariery",
"productForm_effectSoothing": "Łagodzenie", "productForm_effectSoothing": "Łagodzenie",
"productForm_effectExfoliation": "Złuszczanie", "productForm_effectExfoliation": "Złuszczanie",
"productForm_effectRetinoid": "Aktywność retinoidu", "productForm_effectRetinoid": "Aktywność retinoidu",
"productForm_effectIrritation": "Ryzyko podrażnienia", "productForm_effectIrritation": "Ryzyko podrażnienia",
"productForm_effectComedogenic": "Ryzyko komedogenności", "productForm_effectComedogenic": "Ryzyko komedogenności",
"productForm_effectBarrierDisruption": "Ryzyko naruszenia bariery", "productForm_effectBarrierDisruption": "Ryzyko naruszenia bariery",
"productForm_effectDryness": "Ryzyko przesuszenia", "productForm_effectDryness": "Ryzyko przesuszenia",
"productForm_effectBrightening": "Rozjaśnienie", "productForm_effectBrightening": "Rozjaśnienie",
"productForm_effectAntiAcne": "Działanie przeciwtrądzikowe", "productForm_effectAntiAcne": "Działanie przeciwtrądzikowe",
"productForm_effectAntiAging": "Działanie przeciwstarzeniowe", "productForm_effectAntiAging": "Działanie przeciwstarzeniowe",
"lang_pl": "PL", "lang_pl": "PL",
"lang_en": "EN" "lang_en": "EN"
} }

View file

@ -1,12 +1,12 @@
{ {
"$schema": "https://inlang.com/schema/project-settings", "$schema": "https://inlang.com/schema/project-settings",
"baseLocale": "pl", "baseLocale": "pl",
"locales": ["pl", "en"], "locales": ["pl", "en"],
"modules": [ "modules": [
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js", "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js" "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
], ],
"plugin.inlang.messageFormat": { "plugin.inlang.messageFormat": {
"pathPattern": "./messages/{locale}.json" "pathPattern": "./messages/{locale}.json"
} }
} }

View file

@ -5,85 +5,85 @@
/* ── CSS variable definitions (light / dark) ─────────────────────────────── */ /* ── CSS variable definitions (light / dark) ─────────────────────────────── */
:root { :root {
--background: hsl(0 0% 100%); --background: hsl(0 0% 100%);
--foreground: hsl(240 10% 3.9%); --foreground: hsl(240 10% 3.9%);
--card: hsl(0 0% 100%); --card: hsl(0 0% 100%);
--card-foreground: hsl(240 10% 3.9%); --card-foreground: hsl(240 10% 3.9%);
--popover: hsl(0 0% 100%); --popover: hsl(0 0% 100%);
--popover-foreground: hsl(240 10% 3.9%); --popover-foreground: hsl(240 10% 3.9%);
--primary: hsl(240 5.9% 10%); --primary: hsl(240 5.9% 10%);
--primary-foreground: hsl(0 0% 98%); --primary-foreground: hsl(0 0% 98%);
--secondary: hsl(240 4.8% 95.9%); --secondary: hsl(240 4.8% 95.9%);
--secondary-foreground: hsl(240 5.9% 10%); --secondary-foreground: hsl(240 5.9% 10%);
--muted: hsl(240 4.8% 95.9%); --muted: hsl(240 4.8% 95.9%);
--muted-foreground: hsl(240 3.8% 46.1%); --muted-foreground: hsl(240 3.8% 46.1%);
--accent: hsl(240 4.8% 95.9%); --accent: hsl(240 4.8% 95.9%);
--accent-foreground: hsl(240 5.9% 10%); --accent-foreground: hsl(240 5.9% 10%);
--destructive: hsl(0 84.2% 60.2%); --destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: hsl(0 0% 98%); --destructive-foreground: hsl(0 0% 98%);
--border: hsl(240 5.9% 90%); --border: hsl(240 5.9% 90%);
--input: hsl(240 5.9% 90%); --input: hsl(240 5.9% 90%);
--ring: hsl(240 5.9% 10%); --ring: hsl(240 5.9% 10%);
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: hsl(240 10% 3.9%); --background: hsl(240 10% 3.9%);
--foreground: hsl(0 0% 98%); --foreground: hsl(0 0% 98%);
--card: hsl(240 10% 3.9%); --card: hsl(240 10% 3.9%);
--card-foreground: hsl(0 0% 98%); --card-foreground: hsl(0 0% 98%);
--popover: hsl(240 10% 3.9%); --popover: hsl(240 10% 3.9%);
--popover-foreground: hsl(0 0% 98%); --popover-foreground: hsl(0 0% 98%);
--primary: hsl(0 0% 98%); --primary: hsl(0 0% 98%);
--primary-foreground: hsl(240 5.9% 10%); --primary-foreground: hsl(240 5.9% 10%);
--secondary: hsl(240 3.7% 15.9%); --secondary: hsl(240 3.7% 15.9%);
--secondary-foreground: hsl(0 0% 98%); --secondary-foreground: hsl(0 0% 98%);
--muted: hsl(240 3.7% 15.9%); --muted: hsl(240 3.7% 15.9%);
--muted-foreground: hsl(240 5% 64.9%); --muted-foreground: hsl(240 5% 64.9%);
--accent: hsl(240 3.7% 15.9%); --accent: hsl(240 3.7% 15.9%);
--accent-foreground: hsl(0 0% 98%); --accent-foreground: hsl(0 0% 98%);
--destructive: hsl(0 62.8% 30.6%); --destructive: hsl(0 62.8% 30.6%);
--destructive-foreground: hsl(0 0% 98%); --destructive-foreground: hsl(0 0% 98%);
--border: hsl(240 3.7% 15.9%); --border: hsl(240 3.7% 15.9%);
--input: hsl(240 3.7% 15.9%); --input: hsl(240 3.7% 15.9%);
--ring: hsl(240 4.9% 83.9%); --ring: hsl(240 4.9% 83.9%);
} }
/* ── Map CSS vars → Tailwind v4 design tokens ────────────────────────────── */ /* ── Map CSS vars → Tailwind v4 design tokens ────────────────────────────── */
@theme inline { @theme inline {
--color-background: var(--background); --color-background: var(--background);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
--color-card: var(--card); --color-card: var(--card);
--color-card-foreground: var(--card-foreground); --color-card-foreground: var(--card-foreground);
--color-popover: var(--popover); --color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground); --color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary); --color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground); --color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary); --color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground); --color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted); --color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground); --color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent); --color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground); --color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive); --color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground); --color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border); --color-border: var(--border);
--color-input: var(--input); --color-input: var(--input);
--color-ring: var(--ring); --color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px); --radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px); --radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius); --radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px); --radius-xl: calc(var(--radius) + 4px);
} }
/* ── Base resets ─────────────────────────────────────────────────────────── */ /* ── Base resets ─────────────────────────────────────────────────────────── */
* { * {
border-color: var(--border); border-color: var(--border);
} }
body { body {
background-color: var(--background); background-color: var(--background);
color: var(--foreground); color: var(--foreground);
} }

14
frontend/src/app.d.ts vendored
View file

@ -1,13 +1,13 @@
// See https://svelte.dev/docs/kit/types#app.d.ts // See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces // for information about these interfaces
declare global { declare global {
namespace App { namespace App {
// interface Error {} // interface Error {}
// interface Locals {} // interface Locals {}
// interface PageData {} // interface PageData {}
// interface PageState {} // interface PageState {}
// interface Platform {} // interface Platform {}
} }
} }
export {}; export {};

View file

@ -1,11 +1,11 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div> <div style="display: contents">%sveltekit.body%</div>
</body> </body>
</html> </html>

View file

@ -1,6 +1,6 @@
import { paraglideMiddleware } from '$lib/paraglide/server.js'; import { paraglideMiddleware } from "$lib/paraglide/server.js";
import type { Handle } from '@sveltejs/kit'; import type { Handle } from "@sveltejs/kit";
export const handle: Handle = async ({ event, resolve }) => { export const handle: Handle = async ({ event, resolve }) => {
return paraglideMiddleware(event.request, () => resolve(event)); return paraglideMiddleware(event.request, () => resolve(event));
}; };

View file

@ -1,280 +1,349 @@
import { browser } from '$app/environment'; import { browser } from "$app/environment";
import { PUBLIC_API_BASE } from '$env/static/public'; import { PUBLIC_API_BASE } from "$env/static/public";
import type { import type {
ActiveIngredient, ActiveIngredient,
BatchSuggestion, BatchSuggestion,
GroomingSchedule, GroomingSchedule,
LabResult, LabResult,
MedicationEntry, MedicationEntry,
MedicationUsage, MedicationUsage,
PartOfDay, PartOfDay,
Product, Product,
ProductContext, ProductContext,
ProductEffectProfile, ProductEffectProfile,
ProductInteraction, ProductInteraction,
ProductInventory, ProductInventory,
Routine, Routine,
RoutineSuggestion, RoutineSuggestion,
RoutineStep, RoutineStep,
SkinConditionSnapshot SkinConditionSnapshot,
} from './types'; } from "./types";
// ─── Core fetch helpers ────────────────────────────────────────────────────── // ─── Core fetch helpers ──────────────────────────────────────────────────────
async function request<T>(path: string, init: RequestInit = {}): Promise<T> { async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
// Server-side uses PUBLIC_API_BASE (e.g. http://localhost:8000). // Server-side uses PUBLIC_API_BASE (e.g. http://localhost:8000).
// Browser-side uses /api so nginx proxies the request on the correct host. // Browser-side uses /api so nginx proxies the request on the correct host.
const base = browser ? '/api' : PUBLIC_API_BASE; const base = browser ? "/api" : PUBLIC_API_BASE;
const url = `${base}${path}`; const url = `${base}${path}`;
const res = await fetch(url, { const res = await fetch(url, {
headers: { 'Content-Type': 'application/json', ...init.headers }, headers: { "Content-Type": "application/json", ...init.headers },
...init ...init,
}); });
if (!res.ok) { if (!res.ok) {
const detail = await res.json().catch(() => ({ detail: res.statusText })); const detail = await res.json().catch(() => ({ detail: res.statusText }));
throw new Error(detail?.detail ?? res.statusText); throw new Error(detail?.detail ?? res.statusText);
} }
if (res.status === 204) return undefined as T; if (res.status === 204) return undefined as T;
return res.json(); return res.json();
} }
export const api = { export const api = {
get: <T>(path: string) => request<T>(path), get: <T>(path: string) => request<T>(path),
post: <T>(path: string, body: unknown) => post: <T>(path: string, body: unknown) =>
request<T>(path, { method: 'POST', body: JSON.stringify(body) }), request<T>(path, { method: "POST", body: JSON.stringify(body) }),
patch: <T>(path: string, body: unknown) => patch: <T>(path: string, body: unknown) =>
request<T>(path, { method: 'PATCH', body: JSON.stringify(body) }), request<T>(path, { method: "PATCH", body: JSON.stringify(body) }),
del: (path: string) => request<void>(path, { method: 'DELETE' }) del: (path: string) => request<void>(path, { method: "DELETE" }),
}; };
// ─── Products ──────────────────────────────────────────────────────────────── // ─── Products ────────────────────────────────────────────────────────────────
export interface ProductListParams { export interface ProductListParams {
category?: string; category?: string;
brand?: string; brand?: string;
targets?: string[]; targets?: string[];
is_medication?: boolean; is_medication?: boolean;
is_tool?: boolean; is_tool?: boolean;
} }
export function getProducts(params: ProductListParams = {}): Promise<Product[]> { export function getProducts(
const q = new URLSearchParams(); params: ProductListParams = {},
if (params.category) q.set('category', params.category); ): Promise<Product[]> {
if (params.brand) q.set('brand', params.brand); const q = new URLSearchParams();
if (params.targets) params.targets.forEach((t) => q.append('targets', t)); if (params.category) q.set("category", params.category);
if (params.is_medication != null) q.set('is_medication', String(params.is_medication)); if (params.brand) q.set("brand", params.brand);
if (params.is_tool != null) q.set('is_tool', String(params.is_tool)); if (params.targets) params.targets.forEach((t) => q.append("targets", t));
const qs = q.toString(); if (params.is_medication != null)
return api.get(`/products${qs ? `?${qs}` : ''}`); q.set("is_medication", String(params.is_medication));
if (params.is_tool != null) q.set("is_tool", String(params.is_tool));
const qs = q.toString();
return api.get(`/products${qs ? `?${qs}` : ""}`);
} }
export const getProduct = (id: string): Promise<Product> => api.get(`/products/${id}`); export const getProduct = (id: string): Promise<Product> =>
export const createProduct = (body: Record<string, unknown>): Promise<Product> => api.get(`/products/${id}`);
api.post('/products', body); export const createProduct = (
export const updateProduct = (id: string, body: Record<string, unknown>): Promise<Product> => body: Record<string, unknown>,
api.patch(`/products/${id}`, body); ): Promise<Product> => api.post("/products", body);
export const deleteProduct = (id: string): Promise<void> => api.del(`/products/${id}`); export const updateProduct = (
id: string,
body: Record<string, unknown>,
): Promise<Product> => api.patch(`/products/${id}`, body);
export const deleteProduct = (id: string): Promise<void> =>
api.del(`/products/${id}`);
export const getInventory = (productId: string): Promise<ProductInventory[]> => export const getInventory = (productId: string): Promise<ProductInventory[]> =>
api.get(`/products/${productId}/inventory`); api.get(`/products/${productId}/inventory`);
export const createInventory = ( export const createInventory = (
productId: string, productId: string,
body: Record<string, unknown> body: Record<string, unknown>,
): Promise<ProductInventory> => api.post(`/products/${productId}/inventory`, body); ): Promise<ProductInventory> =>
export const updateInventory = (id: string, body: Record<string, unknown>): Promise<ProductInventory> => api.post(`/products/${productId}/inventory`, body);
api.patch(`/inventory/${id}`, body); export const updateInventory = (
export const deleteInventory = (id: string): Promise<void> => api.del(`/inventory/${id}`); id: string,
body: Record<string, unknown>,
): Promise<ProductInventory> => api.patch(`/inventory/${id}`, body);
export const deleteInventory = (id: string): Promise<void> =>
api.del(`/inventory/${id}`);
export interface ProductParseResponse { export interface ProductParseResponse {
name?: string; brand?: string; line_name?: string; sku?: string; url?: string; barcode?: string; name?: string;
category?: string; recommended_time?: string; texture?: string; absorption_speed?: string; brand?: string;
leave_on?: boolean; price_tier?: string; line_name?: string;
size_ml?: number; full_weight_g?: number; empty_weight_g?: number; pao_months?: number; sku?: string;
inci?: string[]; actives?: ActiveIngredient[]; url?: string;
recommended_for?: string[]; targets?: string[]; barcode?: string;
contraindications?: string[]; usage_notes?: string; category?: string;
fragrance_free?: boolean; essential_oils_free?: boolean; recommended_time?: string;
alcohol_denat_free?: boolean; pregnancy_safe?: boolean; texture?: string;
product_effect_profile?: ProductEffectProfile; absorption_speed?: string;
ph_min?: number; ph_max?: number; leave_on?: boolean;
incompatible_with?: ProductInteraction[]; synergizes_with?: string[]; price_tier?: string;
context_rules?: ProductContext; size_ml?: number;
min_interval_hours?: number; max_frequency_per_week?: number; full_weight_g?: number;
is_medication?: boolean; is_tool?: boolean; needle_length_mm?: number; empty_weight_g?: number;
pao_months?: number;
inci?: string[];
actives?: ActiveIngredient[];
recommended_for?: string[];
targets?: string[];
contraindications?: string[];
usage_notes?: string;
fragrance_free?: boolean;
essential_oils_free?: boolean;
alcohol_denat_free?: boolean;
pregnancy_safe?: boolean;
product_effect_profile?: ProductEffectProfile;
ph_min?: number;
ph_max?: number;
incompatible_with?: ProductInteraction[];
synergizes_with?: string[];
context_rules?: ProductContext;
min_interval_hours?: number;
max_frequency_per_week?: number;
is_medication?: boolean;
is_tool?: boolean;
needle_length_mm?: number;
} }
export const parseProductText = (text: string): Promise<ProductParseResponse> => export const parseProductText = (text: string): Promise<ProductParseResponse> =>
api.post('/products/parse-text', { text }); api.post("/products/parse-text", { text });
// ─── Routines ──────────────────────────────────────────────────────────────── // ─── Routines ────────────────────────────────────────────────────────────────
export interface RoutineListParams { export interface RoutineListParams {
from_date?: string; from_date?: string;
to_date?: string; to_date?: string;
part_of_day?: string; part_of_day?: string;
} }
export function getRoutines(params: RoutineListParams = {}): Promise<Routine[]> { export function getRoutines(
const q = new URLSearchParams(); params: RoutineListParams = {},
if (params.from_date) q.set('from_date', params.from_date); ): Promise<Routine[]> {
if (params.to_date) q.set('to_date', params.to_date); const q = new URLSearchParams();
if (params.part_of_day) q.set('part_of_day', params.part_of_day); if (params.from_date) q.set("from_date", params.from_date);
const qs = q.toString(); if (params.to_date) q.set("to_date", params.to_date);
return api.get(`/routines${qs ? `?${qs}` : ''}`); if (params.part_of_day) q.set("part_of_day", params.part_of_day);
const qs = q.toString();
return api.get(`/routines${qs ? `?${qs}` : ""}`);
} }
export const getRoutine = (id: string): Promise<Routine> => api.get(`/routines/${id}`); export const getRoutine = (id: string): Promise<Routine> =>
export const createRoutine = (body: Record<string, unknown>): Promise<Routine> => api.get(`/routines/${id}`);
api.post('/routines', body); export const createRoutine = (
export const updateRoutine = (id: string, body: Record<string, unknown>): Promise<Routine> => body: Record<string, unknown>,
api.patch(`/routines/${id}`, body); ): Promise<Routine> => api.post("/routines", body);
export const deleteRoutine = (id: string): Promise<void> => api.del(`/routines/${id}`); export const updateRoutine = (
id: string,
body: Record<string, unknown>,
): Promise<Routine> => api.patch(`/routines/${id}`, body);
export const deleteRoutine = (id: string): Promise<void> =>
api.del(`/routines/${id}`);
export const addRoutineStep = (routineId: string, body: Record<string, unknown>): Promise<RoutineStep> => export const addRoutineStep = (
api.post(`/routines/${routineId}/steps`, body); routineId: string,
export const updateRoutineStep = (stepId: string, body: Record<string, unknown>): Promise<RoutineStep> => body: Record<string, unknown>,
api.patch(`/routines/steps/${stepId}`, body); ): Promise<RoutineStep> => api.post(`/routines/${routineId}/steps`, body);
export const updateRoutineStep = (
stepId: string,
body: Record<string, unknown>,
): Promise<RoutineStep> => api.patch(`/routines/steps/${stepId}`, body);
export const deleteRoutineStep = (stepId: string): Promise<void> => export const deleteRoutineStep = (stepId: string): Promise<void> =>
api.del(`/routines/steps/${stepId}`); api.del(`/routines/steps/${stepId}`);
export const suggestRoutine = (body: { export const suggestRoutine = (body: {
routine_date: string; routine_date: string;
part_of_day: PartOfDay; part_of_day: PartOfDay;
notes?: string; notes?: string;
include_minoxidil_beard?: boolean; include_minoxidil_beard?: boolean;
leaving_home?: boolean; leaving_home?: boolean;
}): Promise<RoutineSuggestion> => api.post('/routines/suggest', body); }): Promise<RoutineSuggestion> => api.post("/routines/suggest", body);
export const suggestBatch = (body: { export const suggestBatch = (body: {
from_date: string; from_date: string;
to_date: string; to_date: string;
notes?: string; notes?: string;
include_minoxidil_beard?: boolean; include_minoxidil_beard?: boolean;
minimize_products?: boolean; minimize_products?: boolean;
}): Promise<BatchSuggestion> => api.post('/routines/suggest-batch', body); }): Promise<BatchSuggestion> => api.post("/routines/suggest-batch", body);
export const getGroomingSchedule = (): Promise<GroomingSchedule[]> => export const getGroomingSchedule = (): Promise<GroomingSchedule[]> =>
api.get('/routines/grooming-schedule'); api.get("/routines/grooming-schedule");
export const createGroomingScheduleEntry = (body: Record<string, unknown>): Promise<GroomingSchedule> => export const createGroomingScheduleEntry = (
api.post('/routines/grooming-schedule', body); body: Record<string, unknown>,
export const updateGroomingScheduleEntry = (id: string, body: Record<string, unknown>): Promise<GroomingSchedule> => ): Promise<GroomingSchedule> => api.post("/routines/grooming-schedule", body);
api.patch(`/routines/grooming-schedule/${id}`, body); export const updateGroomingScheduleEntry = (
id: string,
body: Record<string, unknown>,
): Promise<GroomingSchedule> =>
api.patch(`/routines/grooming-schedule/${id}`, body);
export const deleteGroomingScheduleEntry = (id: string): Promise<void> => export const deleteGroomingScheduleEntry = (id: string): Promise<void> =>
api.del(`/routines/grooming-schedule/${id}`); api.del(`/routines/grooming-schedule/${id}`);
// ─── Health Medications ──────────────────────────────────────────────────── // ─── Health Medications ────────────────────────────────────────────────────
export interface MedicationListParams { export interface MedicationListParams {
kind?: string; kind?: string;
product_name?: string; product_name?: string;
} }
export function getMedications(params: MedicationListParams = {}): Promise<MedicationEntry[]> { export function getMedications(
const q = new URLSearchParams(); params: MedicationListParams = {},
if (params.kind) q.set('kind', params.kind); ): Promise<MedicationEntry[]> {
if (params.product_name) q.set('product_name', params.product_name); const q = new URLSearchParams();
const qs = q.toString(); if (params.kind) q.set("kind", params.kind);
return api.get(`/health/medications${qs ? `?${qs}` : ''}`); if (params.product_name) q.set("product_name", params.product_name);
const qs = q.toString();
return api.get(`/health/medications${qs ? `?${qs}` : ""}`);
} }
export const getMedication = (id: string): Promise<MedicationEntry> => export const getMedication = (id: string): Promise<MedicationEntry> =>
api.get(`/health/medications/${id}`); api.get(`/health/medications/${id}`);
export const createMedication = (body: Record<string, unknown>): Promise<MedicationEntry> => export const createMedication = (
api.post('/health/medications', body); body: Record<string, unknown>,
): Promise<MedicationEntry> => api.post("/health/medications", body);
export const updateMedication = ( export const updateMedication = (
id: string, id: string,
body: Record<string, unknown> body: Record<string, unknown>,
): Promise<MedicationEntry> => api.patch(`/health/medications/${id}`, body); ): Promise<MedicationEntry> => api.patch(`/health/medications/${id}`, body);
export const deleteMedication = (id: string): Promise<void> => export const deleteMedication = (id: string): Promise<void> =>
api.del(`/health/medications/${id}`); api.del(`/health/medications/${id}`);
export const getMedicationUsages = (medicationId: string): Promise<MedicationUsage[]> => export const getMedicationUsages = (
api.get(`/health/medications/${medicationId}/usages`); medicationId: string,
): Promise<MedicationUsage[]> =>
api.get(`/health/medications/${medicationId}/usages`);
export const createMedicationUsage = ( export const createMedicationUsage = (
medicationId: string, medicationId: string,
body: Record<string, unknown> body: Record<string, unknown>,
): Promise<MedicationUsage> => api.post(`/health/medications/${medicationId}/usages`, body); ): Promise<MedicationUsage> =>
api.post(`/health/medications/${medicationId}/usages`, body);
// ─── Health Lab results ──────────────────────────────────────────────────── // ─── Health Lab results ────────────────────────────────────────────────────
export interface LabResultListParams { export interface LabResultListParams {
test_code?: string; test_code?: string;
flag?: string; flag?: string;
lab?: string; lab?: string;
from_date?: string; from_date?: string;
to_date?: string; to_date?: string;
} }
export function getLabResults(params: LabResultListParams = {}): Promise<LabResult[]> { export function getLabResults(
const q = new URLSearchParams(); params: LabResultListParams = {},
if (params.test_code) q.set('test_code', params.test_code); ): Promise<LabResult[]> {
if (params.flag) q.set('flag', params.flag); const q = new URLSearchParams();
if (params.lab) q.set('lab', params.lab); if (params.test_code) q.set("test_code", params.test_code);
if (params.from_date) q.set('from_date', params.from_date); if (params.flag) q.set("flag", params.flag);
if (params.to_date) q.set('to_date', params.to_date); if (params.lab) q.set("lab", params.lab);
const qs = q.toString(); if (params.from_date) q.set("from_date", params.from_date);
return api.get(`/health/lab-results${qs ? `?${qs}` : ''}`); if (params.to_date) q.set("to_date", params.to_date);
const qs = q.toString();
return api.get(`/health/lab-results${qs ? `?${qs}` : ""}`);
} }
export const getLabResult = (id: string): Promise<LabResult> => export const getLabResult = (id: string): Promise<LabResult> =>
api.get(`/health/lab-results/${id}`); api.get(`/health/lab-results/${id}`);
export const createLabResult = (body: Record<string, unknown>): Promise<LabResult> => export const createLabResult = (
api.post('/health/lab-results', body); body: Record<string, unknown>,
export const updateLabResult = (id: string, body: Record<string, unknown>): Promise<LabResult> => ): Promise<LabResult> => api.post("/health/lab-results", body);
api.patch(`/health/lab-results/${id}`, body); export const updateLabResult = (
id: string,
body: Record<string, unknown>,
): Promise<LabResult> => api.patch(`/health/lab-results/${id}`, body);
export const deleteLabResult = (id: string): Promise<void> => export const deleteLabResult = (id: string): Promise<void> =>
api.del(`/health/lab-results/${id}`); api.del(`/health/lab-results/${id}`);
// ─── Skin ──────────────────────────────────────────────────────────────────── // ─── Skin ────────────────────────────────────────────────────────────────────
export interface SnapshotListParams { export interface SnapshotListParams {
from_date?: string; from_date?: string;
to_date?: string; to_date?: string;
overall_state?: string; overall_state?: string;
} }
export function getSkinSnapshots(params: SnapshotListParams = {}): Promise<SkinConditionSnapshot[]> { export function getSkinSnapshots(
const q = new URLSearchParams(); params: SnapshotListParams = {},
if (params.from_date) q.set('from_date', params.from_date); ): Promise<SkinConditionSnapshot[]> {
if (params.to_date) q.set('to_date', params.to_date); const q = new URLSearchParams();
if (params.overall_state) q.set('overall_state', params.overall_state); if (params.from_date) q.set("from_date", params.from_date);
const qs = q.toString(); if (params.to_date) q.set("to_date", params.to_date);
return api.get(`/skincare${qs ? `?${qs}` : ''}`); if (params.overall_state) q.set("overall_state", params.overall_state);
const qs = q.toString();
return api.get(`/skincare${qs ? `?${qs}` : ""}`);
} }
export const getSkinSnapshot = (id: string): Promise<SkinConditionSnapshot> => export const getSkinSnapshot = (id: string): Promise<SkinConditionSnapshot> =>
api.get(`/skincare/${id}`); api.get(`/skincare/${id}`);
export const createSkinSnapshot = (body: Record<string, unknown>): Promise<SkinConditionSnapshot> => export const createSkinSnapshot = (
api.post('/skincare', body); body: Record<string, unknown>,
): Promise<SkinConditionSnapshot> => api.post("/skincare", body);
export const updateSkinSnapshot = ( export const updateSkinSnapshot = (
id: string, id: string,
body: Record<string, unknown> body: Record<string, unknown>,
): Promise<SkinConditionSnapshot> => api.patch(`/skincare/${id}`, body); ): Promise<SkinConditionSnapshot> => api.patch(`/skincare/${id}`, body);
export const deleteSkinSnapshot = (id: string): Promise<void> => api.del(`/skincare/${id}`); export const deleteSkinSnapshot = (id: string): Promise<void> =>
api.del(`/skincare/${id}`);
export interface SkinPhotoAnalysisResponse { export interface SkinPhotoAnalysisResponse {
overall_state?: string; overall_state?: string;
texture?: string; texture?: string;
skin_type?: string; skin_type?: string;
hydration_level?: number; hydration_level?: number;
sebum_tzone?: number; sebum_tzone?: number;
sebum_cheeks?: number; sebum_cheeks?: number;
sensitivity_level?: number; sensitivity_level?: number;
barrier_state?: string; barrier_state?: string;
active_concerns?: string[]; active_concerns?: string[];
risks?: string[]; risks?: string[];
priorities?: string[]; priorities?: string[];
notes?: string; notes?: string;
} }
export async function analyzeSkinPhotos(files: File[]): Promise<SkinPhotoAnalysisResponse> { export async function analyzeSkinPhotos(
const body = new FormData(); files: File[],
for (const file of files) body.append('photos', file); ): Promise<SkinPhotoAnalysisResponse> {
const base = browser ? '/api' : PUBLIC_API_BASE; const body = new FormData();
const res = await fetch(`${base}/skincare/analyze-photos`, { method: 'POST', body }); for (const file of files) body.append("photos", file);
if (!res.ok) { const base = browser ? "/api" : PUBLIC_API_BASE;
const detail = await res.json().catch(() => ({ detail: res.statusText })); const res = await fetch(`${base}/skincare/analyze-photos`, {
throw new Error(detail?.detail ?? res.statusText); method: "POST",
} body,
return res.json(); });
if (!res.ok) {
const detail = await res.json().catch(() => ({ detail: res.statusText }));
throw new Error(detail?.detail ?? res.statusText);
}
return res.json();
} }

View file

@ -1,17 +1,17 @@
import Root, { import Root, {
type ButtonProps, type ButtonProps,
type ButtonSize, type ButtonSize,
type ButtonVariant, type ButtonVariant,
buttonVariants, buttonVariants,
} from "./button.svelte"; } from "./button.svelte";
export { export {
Root, Root,
type ButtonProps as Props, type ButtonProps as Props,
// //
Root as Button, Root as Button,
buttonVariants, buttonVariants,
type ButtonProps, type ButtonProps,
type ButtonSize, type ButtonSize,
type ButtonVariant, type ButtonVariant,
}; };

View file

@ -7,19 +7,19 @@ import Title from "./card-title.svelte";
import Action from "./card-action.svelte"; import Action from "./card-action.svelte";
export { export {
Root, Root,
Content, Content,
Description, Description,
Footer, Footer,
Header, Header,
Title, Title,
Action, Action,
// //
Root as Card, Root as Card,
Content as CardContent, Content as CardContent,
Description as CardDescription, Description as CardDescription,
Footer as CardFooter, Footer as CardFooter,
Header as CardHeader, Header as CardHeader,
Title as CardTitle, Title as CardTitle,
Action as CardAction, Action as CardAction,
}; };

View file

@ -1,7 +1,7 @@
import Root from "./input.svelte"; import Root from "./input.svelte";
export { export {
Root, Root,
// //
Root as Input, Root as Input,
}; };

View file

@ -1,7 +1,7 @@
import Root from "./label.svelte"; import Root from "./label.svelte";
export { export {
Root, Root,
// //
Root as Label, Root as Label,
}; };

View file

@ -11,27 +11,27 @@ import GroupHeading from "./select-group-heading.svelte";
import Portal from "./select-portal.svelte"; import Portal from "./select-portal.svelte";
export { export {
Root, Root,
Group, Group,
Label, Label,
Item, Item,
Content, Content,
Trigger, Trigger,
Separator, Separator,
ScrollDownButton, ScrollDownButton,
ScrollUpButton, ScrollUpButton,
GroupHeading, GroupHeading,
Portal, Portal,
// //
Root as Select, Root as Select,
Group as SelectGroup, Group as SelectGroup,
Label as SelectLabel, Label as SelectLabel,
Item as SelectItem, Item as SelectItem,
Content as SelectContent, Content as SelectContent,
Trigger as SelectTrigger, Trigger as SelectTrigger,
Separator as SelectSeparator, Separator as SelectSeparator,
ScrollDownButton as SelectScrollDownButton, ScrollDownButton as SelectScrollDownButton,
ScrollUpButton as SelectScrollUpButton, ScrollUpButton as SelectScrollUpButton,
GroupHeading as SelectGroupHeading, GroupHeading as SelectGroupHeading,
Portal as SelectPortal, Portal as SelectPortal,
}; };

View file

@ -1,7 +1,7 @@
import Root from "./separator.svelte"; import Root from "./separator.svelte";
export { export {
Root, Root,
// //
Root as Separator, Root as Separator,
}; };

View file

@ -8,21 +8,21 @@ import Header from "./table-header.svelte";
import Row from "./table-row.svelte"; import Row from "./table-row.svelte";
export { export {
Root, Root,
Body, Body,
Caption, Caption,
Cell, Cell,
Footer, Footer,
Head, Head,
Header, Header,
Row, Row,
// //
Root as Table, Root as Table,
Body as TableBody, Body as TableBody,
Caption as TableCaption, Caption as TableCaption,
Cell as TableCell, Cell as TableCell,
Footer as TableFooter, Footer as TableFooter,
Head as TableHead, Head as TableHead,
Header as TableHeader, Header as TableHeader,
Row as TableRow, Row as TableRow,
}; };

View file

@ -4,13 +4,13 @@ import List from "./tabs-list.svelte";
import Trigger from "./tabs-trigger.svelte"; import Trigger from "./tabs-trigger.svelte";
export { export {
Root, Root,
Content, Content,
List, List,
Trigger, Trigger,
// //
Root as Tabs, Root as Tabs,
Content as TabsContent, Content as TabsContent,
List as TabsList, List as TabsList,
Trigger as TabsTrigger, Trigger as TabsTrigger,
}; };

View file

@ -1,308 +1,335 @@
// ─── Enums ────────────────────────────────────────────────────────────────── // ─── Enums ──────────────────────────────────────────────────────────────────
export type AbsorptionSpeed = 'very_fast' | 'fast' | 'moderate' | 'slow' | 'very_slow'; export type AbsorptionSpeed =
export type BarrierState = 'intact' | 'mildly_compromised' | 'compromised'; | "very_fast"
export type DayTime = 'am' | 'pm' | 'both'; | "fast"
export type GroomingAction = 'shaving_razor' | 'shaving_oneblade' | 'dermarolling'; | "moderate"
| "slow"
| "very_slow";
export type BarrierState = "intact" | "mildly_compromised" | "compromised";
export type DayTime = "am" | "pm" | "both";
export type GroomingAction =
| "shaving_razor"
| "shaving_oneblade"
| "dermarolling";
export type IngredientFunction = export type IngredientFunction =
| 'humectant' | "humectant"
| 'emollient' | "emollient"
| 'occlusive' | "occlusive"
| 'exfoliant_aha' | "exfoliant_aha"
| 'exfoliant_bha' | "exfoliant_bha"
| 'exfoliant_pha' | "exfoliant_pha"
| 'retinoid' | "retinoid"
| 'antioxidant' | "antioxidant"
| 'soothing' | "soothing"
| 'barrier_support' | "barrier_support"
| 'brightening' | "brightening"
| 'anti_acne' | "anti_acne"
| 'ceramide' | "ceramide"
| 'niacinamide' | "niacinamide"
| 'sunscreen' | "sunscreen"
| 'peptide' | "peptide"
| 'hair_growth_stimulant' | "hair_growth_stimulant"
| 'prebiotic' | "prebiotic"
| 'vitamin_c' | "vitamin_c"
| 'anti_aging'; | "anti_aging";
export type InteractionScope = 'same_step' | 'same_day' | 'same_period'; export type InteractionScope = "same_step" | "same_day" | "same_period";
export type MedicationKind = 'prescription' | 'otc' | 'supplement' | 'herbal' | 'other'; export type MedicationKind =
export type OverallSkinState = 'excellent' | 'good' | 'fair' | 'poor'; | "prescription"
export type PartOfDay = 'am' | 'pm'; | "otc"
export type PriceTier = 'budget' | 'mid' | 'premium' | 'luxury'; | "supplement"
| "herbal"
| "other";
export type OverallSkinState = "excellent" | "good" | "fair" | "poor";
export type PartOfDay = "am" | "pm";
export type PriceTier = "budget" | "mid" | "premium" | "luxury";
export type ProductCategory = export type ProductCategory =
| 'cleanser' | "cleanser"
| 'toner' | "toner"
| 'essence' | "essence"
| 'serum' | "serum"
| 'moisturizer' | "moisturizer"
| 'spf' | "spf"
| 'mask' | "mask"
| 'exfoliant' | "exfoliant"
| 'hair_treatment' | "hair_treatment"
| 'tool' | "tool"
| 'spot_treatment' | "spot_treatment"
| 'oil'; | "oil";
export type ResultFlag = 'N' | 'ABN' | 'POS' | 'NEG' | 'L' | 'H'; export type ResultFlag = "N" | "ABN" | "POS" | "NEG" | "L" | "H";
export type SkinConcern = export type SkinConcern =
| 'acne' | "acne"
| 'rosacea' | "rosacea"
| 'hyperpigmentation' | "hyperpigmentation"
| 'aging' | "aging"
| 'dehydration' | "dehydration"
| 'redness' | "redness"
| 'damaged_barrier' | "damaged_barrier"
| 'pore_visibility' | "pore_visibility"
| 'uneven_texture' | "uneven_texture"
| 'hair_growth' | "hair_growth"
| 'sebum_excess'; | "sebum_excess";
export type SkinTexture = 'smooth' | 'rough' | 'flaky' | 'bumpy'; export type SkinTexture = "smooth" | "rough" | "flaky" | "bumpy";
export type SkinType = 'dry' | 'oily' | 'combination' | 'sensitive' | 'normal' | 'acne_prone'; export type SkinType =
| "dry"
| "oily"
| "combination"
| "sensitive"
| "normal"
| "acne_prone";
export type StrengthLevel = 1 | 2 | 3; export type StrengthLevel = 1 | 2 | 3;
export type TextureType = 'watery' | 'gel' | 'emulsion' | 'cream' | 'oil' | 'balm' | 'foam' | 'fluid'; export type TextureType =
| "watery"
| "gel"
| "emulsion"
| "cream"
| "oil"
| "balm"
| "foam"
| "fluid";
// ─── Product types ─────────────────────────────────────────────────────────── // ─── Product types ───────────────────────────────────────────────────────────
export interface ActiveIngredient { export interface ActiveIngredient {
name: string; name: string;
percent?: number; percent?: number;
functions: IngredientFunction[]; functions: IngredientFunction[];
strength_level?: StrengthLevel; strength_level?: StrengthLevel;
irritation_potential?: StrengthLevel; irritation_potential?: StrengthLevel;
} }
export interface ProductEffectProfile { export interface ProductEffectProfile {
hydration_immediate: number; hydration_immediate: number;
hydration_long_term: number; hydration_long_term: number;
barrier_repair_strength: number; barrier_repair_strength: number;
soothing_strength: number; soothing_strength: number;
exfoliation_strength: number; exfoliation_strength: number;
retinoid_strength: number; retinoid_strength: number;
irritation_risk: number; irritation_risk: number;
comedogenic_risk: number; comedogenic_risk: number;
barrier_disruption_risk: number; barrier_disruption_risk: number;
dryness_risk: number; dryness_risk: number;
brightening_strength: number; brightening_strength: number;
anti_acne_strength: number; anti_acne_strength: number;
anti_aging_strength: number; anti_aging_strength: number;
} }
export interface ProductInteraction { export interface ProductInteraction {
target: string; target: string;
scope: InteractionScope; scope: InteractionScope;
reason?: string; reason?: string;
} }
export interface ProductContext { export interface ProductContext {
safe_after_shaving?: boolean; safe_after_shaving?: boolean;
safe_after_acids?: boolean; safe_after_acids?: boolean;
safe_after_retinoids?: boolean; safe_after_retinoids?: boolean;
safe_with_compromised_barrier?: boolean; safe_with_compromised_barrier?: boolean;
low_uv_only?: boolean; low_uv_only?: boolean;
} }
export interface ProductInventory { export interface ProductInventory {
id: string; id: string;
product_id: string; product_id: string;
is_opened: boolean; is_opened: boolean;
opened_at?: string; opened_at?: string;
finished_at?: string; finished_at?: string;
expiry_date?: string; expiry_date?: string;
current_weight_g?: number; current_weight_g?: number;
last_weighed_at?: string; last_weighed_at?: string;
notes?: string; notes?: string;
created_at: string; created_at: string;
product?: Product; product?: Product;
} }
export interface Product { export interface Product {
id: string; id: string;
name: string; name: string;
brand: string; brand: string;
line_name?: string; line_name?: string;
sku?: string; sku?: string;
url?: string; url?: string;
barcode?: string; barcode?: string;
category: ProductCategory; category: ProductCategory;
recommended_time: DayTime; recommended_time: DayTime;
texture?: TextureType; texture?: TextureType;
absorption_speed?: AbsorptionSpeed; absorption_speed?: AbsorptionSpeed;
leave_on: boolean; leave_on: boolean;
price_tier?: PriceTier; price_tier?: PriceTier;
size_ml?: number; size_ml?: number;
full_weight_g?: number; full_weight_g?: number;
empty_weight_g?: number; empty_weight_g?: number;
pao_months?: number; pao_months?: number;
inci: string[]; inci: string[];
actives?: ActiveIngredient[]; actives?: ActiveIngredient[];
recommended_for: SkinType[]; recommended_for: SkinType[];
targets: SkinConcern[]; targets: SkinConcern[];
contraindications: string[]; contraindications: string[];
usage_notes?: string; usage_notes?: string;
fragrance_free?: boolean; fragrance_free?: boolean;
essential_oils_free?: boolean; essential_oils_free?: boolean;
alcohol_denat_free?: boolean; alcohol_denat_free?: boolean;
pregnancy_safe?: boolean; pregnancy_safe?: boolean;
product_effect_profile: ProductEffectProfile; product_effect_profile: ProductEffectProfile;
ph_min?: number; ph_min?: number;
ph_max?: number; ph_max?: number;
incompatible_with?: ProductInteraction[]; incompatible_with?: ProductInteraction[];
synergizes_with?: string[]; synergizes_with?: string[];
context_rules?: ProductContext; context_rules?: ProductContext;
min_interval_hours?: number; min_interval_hours?: number;
max_frequency_per_week?: number; max_frequency_per_week?: number;
is_medication: boolean; is_medication: boolean;
is_tool: boolean; is_tool: boolean;
needle_length_mm?: number; needle_length_mm?: number;
personal_tolerance_notes?: string; personal_tolerance_notes?: string;
personal_repurchase_intent?: boolean; personal_repurchase_intent?: boolean;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
inventory: ProductInventory[]; inventory: ProductInventory[];
} }
// ─── Routine types ─────────────────────────────────────────────────────────── // ─── Routine types ───────────────────────────────────────────────────────────
export interface RoutineStep { export interface RoutineStep {
id: string; id: string;
routine_id: string; routine_id: string;
product_id?: string; product_id?: string;
order_index: number; order_index: number;
action_type?: GroomingAction; action_type?: GroomingAction;
action_notes?: string; action_notes?: string;
dose?: string; dose?: string;
region?: string; region?: string;
product?: Product; product?: Product;
} }
export interface Routine { export interface Routine {
id: string; id: string;
routine_date: string; routine_date: string;
part_of_day: PartOfDay; part_of_day: PartOfDay;
notes?: string; notes?: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
steps?: RoutineStep[]; steps?: RoutineStep[];
} }
export interface GroomingSchedule { export interface GroomingSchedule {
id: string; id: string;
day_of_week: number; day_of_week: number;
action: GroomingAction; action: GroomingAction;
notes?: string; notes?: string;
} }
export interface SuggestedStep { export interface SuggestedStep {
product_id?: string; product_id?: string;
action_type?: GroomingAction; action_type?: GroomingAction;
action_notes?: string; action_notes?: string;
dose?: string; dose?: string;
region?: string; region?: string;
} }
export interface RoutineSuggestion { export interface RoutineSuggestion {
steps: SuggestedStep[]; steps: SuggestedStep[];
reasoning: string; reasoning: string;
} }
export interface DayPlan { export interface DayPlan {
date: string; date: string;
am_steps: SuggestedStep[]; am_steps: SuggestedStep[];
pm_steps: SuggestedStep[]; pm_steps: SuggestedStep[];
reasoning: string; reasoning: string;
} }
export interface BatchSuggestion { export interface BatchSuggestion {
days: DayPlan[]; days: DayPlan[];
overall_reasoning: string; overall_reasoning: string;
} }
// ─── Shopping suggestion types ─────────────────────────────────────────────── // ─── Shopping suggestion types ───────────────────────────────────────────────
export interface ProductSuggestion { export interface ProductSuggestion {
category: string; category: string;
product_type: string; product_type: string;
key_ingredients: string[]; key_ingredients: string[];
target_concerns: string[]; target_concerns: string[];
why_needed: string; why_needed: string;
recommended_time: string; recommended_time: string;
frequency: string; frequency: string;
} }
export interface ShoppingSuggestionResponse { export interface ShoppingSuggestionResponse {
suggestions: ProductSuggestion[]; suggestions: ProductSuggestion[];
reasoning: string; reasoning: string;
} }
// ─── Health types ──────────────────────────────────────────────────────────── // ─── Health types ────────────────────────────────────────────────────────────
export interface MedicationUsage { export interface MedicationUsage {
record_id: string; record_id: string;
medication_record_id: string; medication_record_id: string;
dose_value?: number; dose_value?: number;
dose_unit?: string; dose_unit?: string;
frequency?: string; frequency?: string;
schedule_text?: string; schedule_text?: string;
as_needed: boolean; as_needed: boolean;
valid_from: string; valid_from: string;
valid_to?: string; valid_to?: string;
source_file?: string; source_file?: string;
notes?: string; notes?: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
} }
export interface MedicationEntry { export interface MedicationEntry {
record_id: string; record_id: string;
kind: MedicationKind; kind: MedicationKind;
product_name: string; product_name: string;
active_substance?: string; active_substance?: string;
formulation?: string; formulation?: string;
route?: string; route?: string;
source_file?: string; source_file?: string;
notes?: string; notes?: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
usage_history: MedicationUsage[]; usage_history: MedicationUsage[];
} }
export interface LabResult { export interface LabResult {
record_id: string; record_id: string;
collected_at: string; collected_at: string;
test_code: string; test_code: string;
test_name_original?: string; test_name_original?: string;
test_name_loinc?: string; test_name_loinc?: string;
value_num?: number; value_num?: number;
value_text?: string; value_text?: string;
value_bool?: boolean; value_bool?: boolean;
unit_original?: string; unit_original?: string;
unit_ucum?: string; unit_ucum?: string;
ref_low?: number; ref_low?: number;
ref_high?: number; ref_high?: number;
ref_text?: string; ref_text?: string;
flag?: ResultFlag; flag?: ResultFlag;
lab?: string; lab?: string;
source_file?: string; source_file?: string;
notes?: string; notes?: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
} }
// ─── Skin types ────────────────────────────────────────────────────────────── // ─── Skin types ──────────────────────────────────────────────────────────────
export interface SkinConditionSnapshot { export interface SkinConditionSnapshot {
id: string; id: string;
snapshot_date: string; snapshot_date: string;
overall_state?: OverallSkinState; overall_state?: OverallSkinState;
skin_type?: SkinType; skin_type?: SkinType;
texture?: SkinTexture; texture?: SkinTexture;
hydration_level?: number; hydration_level?: number;
sebum_tzone?: number; sebum_tzone?: number;
sebum_cheeks?: number; sebum_cheeks?: number;
sensitivity_level?: number; sensitivity_level?: number;
barrier_state?: BarrierState; barrier_state?: BarrierState;
active_concerns: SkinConcern[]; active_concerns: SkinConcern[];
risks: string[]; risks: string[];
priorities: string[]; priorities: string[];
notes?: string; notes?: string;
created_at: string; created_at: string;
} }