chore(frontend): format files with prettier
This commit is contained in:
parent
0e7a39836f
commit
067e460dd2
20 changed files with 1615 additions and 1509 deletions
10
frontend/.mcp.json
Normal file
10
frontend/.mcp.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"mcpServers": {
|
||||
"svelte": {
|
||||
"type": "stdio",
|
||||
"command": "npx",
|
||||
"env": {},
|
||||
"args": ["-y", "@sveltejs/mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,8 @@ The backend must be running at `http://localhost:8000`. See `../backend/` for se
|
|||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|---|---|---|
|
||||
| Variable | Description | Default |
|
||||
| ----------------- | ------------------------------- | ----------------------- |
|
||||
| `PUBLIC_API_BASE` | Base URL of the FastAPI backend | `http://localhost:8000` |
|
||||
|
||||
Set `PUBLIC_API_BASE` at **build time** for production:
|
||||
|
|
@ -51,24 +51,24 @@ Or use the provided systemd service: `../systemd/innercontext-node.service`.
|
|||
|
||||
## Routes
|
||||
|
||||
| Route | Description |
|
||||
|---|---|
|
||||
| `/` | Dashboard |
|
||||
| `/products` | Product list |
|
||||
| `/products/new` | Add product |
|
||||
| `/products/[id]` | Product detail / edit |
|
||||
| `/routines` | Routine list |
|
||||
| `/routines/new` | Create routine |
|
||||
| `/routines/[id]` | Routine detail |
|
||||
| `/health/medications` | Medications |
|
||||
| `/health/lab-results` | Lab results |
|
||||
| `/skin` | Skin condition snapshots |
|
||||
| Route | Description |
|
||||
| --------------------- | ------------------------ |
|
||||
| `/` | Dashboard |
|
||||
| `/products` | Product list |
|
||||
| `/products/new` | Add product |
|
||||
| `/products/[id]` | Product detail / edit |
|
||||
| `/routines` | Routine list |
|
||||
| `/routines/new` | Create routine |
|
||||
| `/routines/[id]` | Routine detail |
|
||||
| `/health/medications` | Medications |
|
||||
| `/health/lab-results` | Lab results |
|
||||
| `/skin` | Skin condition snapshots |
|
||||
|
||||
## Key files
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `src/lib/api.ts` | API client (typed fetch wrappers) |
|
||||
| `src/lib/types.ts` | Shared TypeScript types |
|
||||
| `src/app.css` | Tailwind v4 theme + global styles |
|
||||
| `svelte.config.js` | SvelteKit config (adapter-node) |
|
||||
| File | Purpose |
|
||||
| ------------------ | --------------------------------- |
|
||||
| `src/lib/api.ts` | API client (typed fetch wrappers) |
|
||||
| `src/lib/types.ts` | Shared TypeScript types |
|
||||
| `src/app.css` | Tailwind v4 theme + global styles |
|
||||
| `svelte.config.js` | SvelteKit config (adapter-node) |
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||
"style": "default",
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/app.css",
|
||||
"baseColor": "zinc"
|
||||
},
|
||||
"aliases": {
|
||||
"components": "$lib/components",
|
||||
"utils": "$lib/utils",
|
||||
"ui": "$lib/components/ui",
|
||||
"hooks": "$lib/hooks",
|
||||
"lib": "$lib"
|
||||
},
|
||||
"registry": "https://shadcn-svelte.com/registry"
|
||||
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||
"style": "default",
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/app.css",
|
||||
"baseColor": "zinc"
|
||||
},
|
||||
"aliases": {
|
||||
"components": "$lib/components",
|
||||
"utils": "$lib/utils",
|
||||
"ui": "$lib/components/ui",
|
||||
"hooks": "$lib/hooks",
|
||||
"lib": "$lib"
|
||||
},
|
||||
"registry": "https://shadcn-svelte.com/registry"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,455 +1,455 @@
|
|||
{
|
||||
"nav_dashboard": "Dashboard",
|
||||
"nav_products": "Products",
|
||||
"nav_routines": "Routines",
|
||||
"nav_grooming": "Grooming",
|
||||
"nav_medications": "Medications",
|
||||
"nav_labResults": "Lab Results",
|
||||
"nav_skin": "Skin",
|
||||
"nav_appName": "innercontext",
|
||||
"nav_appSubtitle": "personal health & skincare",
|
||||
"nav_dashboard": "Dashboard",
|
||||
"nav_products": "Products",
|
||||
"nav_routines": "Routines",
|
||||
"nav_grooming": "Grooming",
|
||||
"nav_medications": "Medications",
|
||||
"nav_labResults": "Lab Results",
|
||||
"nav_skin": "Skin",
|
||||
"nav_appName": "innercontext",
|
||||
"nav_appSubtitle": "personal health & skincare",
|
||||
|
||||
"common_save": "Save",
|
||||
"common_cancel": "Cancel",
|
||||
"common_add": "Add",
|
||||
"common_edit": "Edit",
|
||||
"common_delete": "Delete",
|
||||
"common_saved": "Saved.",
|
||||
"common_select": "Select",
|
||||
"common_unknown": "Unknown",
|
||||
"common_yes": "Yes",
|
||||
"common_no": "No",
|
||||
"common_unknown_value": "Unknown",
|
||||
"common_optional_notes": "optional",
|
||||
"common_steps": "steps",
|
||||
"common_save": "Save",
|
||||
"common_cancel": "Cancel",
|
||||
"common_add": "Add",
|
||||
"common_edit": "Edit",
|
||||
"common_delete": "Delete",
|
||||
"common_saved": "Saved.",
|
||||
"common_select": "Select",
|
||||
"common_unknown": "Unknown",
|
||||
"common_yes": "Yes",
|
||||
"common_no": "No",
|
||||
"common_unknown_value": "Unknown",
|
||||
"common_optional_notes": "optional",
|
||||
"common_steps": "steps",
|
||||
|
||||
"dashboard_title": "Dashboard",
|
||||
"dashboard_subtitle": "Your recent health & skincare overview",
|
||||
"dashboard_latestSnapshot": "Latest Skin Snapshot",
|
||||
"dashboard_recentRoutines": "Recent Routines",
|
||||
"dashboard_noSnapshots": "No skin snapshots yet.",
|
||||
"dashboard_noRoutines": "No routines in the past 2 weeks.",
|
||||
"dashboard_title": "Dashboard",
|
||||
"dashboard_subtitle": "Your recent health & skincare overview",
|
||||
"dashboard_latestSnapshot": "Latest Skin Snapshot",
|
||||
"dashboard_recentRoutines": "Recent Routines",
|
||||
"dashboard_noSnapshots": "No skin snapshots yet.",
|
||||
"dashboard_noRoutines": "No routines in the past 2 weeks.",
|
||||
|
||||
"products_title": "Products",
|
||||
"products_count": "{count} products",
|
||||
"products_addNew": "+ Add product",
|
||||
"products_suggest": "Suggest",
|
||||
"products_suggestTitle": "Shopping suggestions",
|
||||
"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_suggestGenerating": "Analyzing...",
|
||||
"products_suggestBtn": "Generate suggestions",
|
||||
"products_suggestResults": "Suggestions",
|
||||
"products_suggestTime": "Time",
|
||||
"products_suggestFrequency": "Frequency",
|
||||
"products_suggestRegenerate": "Regenerate",
|
||||
"products_suggestNoResults": "No suggestions.",
|
||||
"products_noProducts": "No products found.",
|
||||
"products_filterAll": "All",
|
||||
"products_filterOwned": "Owned",
|
||||
"products_filterUnowned": "Not owned",
|
||||
"products_colName": "Name",
|
||||
"products_colBrand": "Brand",
|
||||
"products_colTargets": "Targets",
|
||||
"products_colTime": "Time",
|
||||
"products_newTitle": "New Product",
|
||||
"products_backToList": "← Products",
|
||||
"products_createProduct": "Create product",
|
||||
"products_saveChanges": "Save changes",
|
||||
"products_deleteProduct": "Delete product",
|
||||
"products_confirmDelete": "Delete this product?",
|
||||
"products_noInventory": "No inventory packages.",
|
||||
"products_title": "Products",
|
||||
"products_count": "{count} products",
|
||||
"products_addNew": "+ Add product",
|
||||
"products_suggest": "Suggest",
|
||||
"products_suggestTitle": "Shopping suggestions",
|
||||
"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_suggestGenerating": "Analyzing...",
|
||||
"products_suggestBtn": "Generate suggestions",
|
||||
"products_suggestResults": "Suggestions",
|
||||
"products_suggestTime": "Time",
|
||||
"products_suggestFrequency": "Frequency",
|
||||
"products_suggestRegenerate": "Regenerate",
|
||||
"products_suggestNoResults": "No suggestions.",
|
||||
"products_noProducts": "No products found.",
|
||||
"products_filterAll": "All",
|
||||
"products_filterOwned": "Owned",
|
||||
"products_filterUnowned": "Not owned",
|
||||
"products_colName": "Name",
|
||||
"products_colBrand": "Brand",
|
||||
"products_colTargets": "Targets",
|
||||
"products_colTime": "Time",
|
||||
"products_newTitle": "New Product",
|
||||
"products_backToList": "← Products",
|
||||
"products_createProduct": "Create product",
|
||||
"products_saveChanges": "Save changes",
|
||||
"products_deleteProduct": "Delete product",
|
||||
"products_confirmDelete": "Delete this product?",
|
||||
"products_noInventory": "No inventory packages.",
|
||||
|
||||
"inventory_title": "Inventory packages ({count})",
|
||||
"inventory_addPackage": "+ Add package",
|
||||
"inventory_packageAdded": "Package added.",
|
||||
"inventory_packageUpdated": "Package updated.",
|
||||
"inventory_packageDeleted": "Package deleted.",
|
||||
"inventory_alreadyOpened": "Already opened",
|
||||
"inventory_openedDate": "Opened date",
|
||||
"inventory_finishedDate": "Finished date",
|
||||
"inventory_expiryDate": "Expiry date",
|
||||
"inventory_currentWeight": "Current weight (g)",
|
||||
"inventory_lastWeighed": "Last weighed",
|
||||
"inventory_notes": "Notes",
|
||||
"inventory_badgeOpen": "Open",
|
||||
"inventory_badgeSealed": "Sealed",
|
||||
"inventory_badgeFinished": "Finished",
|
||||
"inventory_exp": "Exp:",
|
||||
"inventory_opened": "Opened:",
|
||||
"inventory_finished": "Finished:",
|
||||
"inventory_remaining": "g remaining",
|
||||
"inventory_weighed": "Weighed:",
|
||||
"inventory_confirmDelete": "Delete this package?",
|
||||
"inventory_title": "Inventory packages ({count})",
|
||||
"inventory_addPackage": "+ Add package",
|
||||
"inventory_packageAdded": "Package added.",
|
||||
"inventory_packageUpdated": "Package updated.",
|
||||
"inventory_packageDeleted": "Package deleted.",
|
||||
"inventory_alreadyOpened": "Already opened",
|
||||
"inventory_openedDate": "Opened date",
|
||||
"inventory_finishedDate": "Finished date",
|
||||
"inventory_expiryDate": "Expiry date",
|
||||
"inventory_currentWeight": "Current weight (g)",
|
||||
"inventory_lastWeighed": "Last weighed",
|
||||
"inventory_notes": "Notes",
|
||||
"inventory_badgeOpen": "Open",
|
||||
"inventory_badgeSealed": "Sealed",
|
||||
"inventory_badgeFinished": "Finished",
|
||||
"inventory_exp": "Exp:",
|
||||
"inventory_opened": "Opened:",
|
||||
"inventory_finished": "Finished:",
|
||||
"inventory_remaining": "g remaining",
|
||||
"inventory_weighed": "Weighed:",
|
||||
"inventory_confirmDelete": "Delete this package?",
|
||||
|
||||
"routines_title": "Routines",
|
||||
"routines_count": "{count} routines (last 30 days)",
|
||||
"routines_suggestAI": "Suggest AI routine",
|
||||
"routines_addNew": "+ New routine",
|
||||
"routines_noRoutines": "No routines found.",
|
||||
"routines_newTitle": "New Routine",
|
||||
"routines_backToList": "← Routines",
|
||||
"routines_detailsTitle": "Routine details",
|
||||
"routines_date": "Date *",
|
||||
"routines_amOrPm": "AM or PM *",
|
||||
"routines_notes": "Notes",
|
||||
"routines_notesPlaceholder": "Optional notes",
|
||||
"routines_createRoutine": "Create routine",
|
||||
"routines_deleteRoutine": "Delete routine",
|
||||
"routines_confirmDelete": "Delete this routine?",
|
||||
"routines_steps": "Steps ({count})",
|
||||
"routines_addStep": "+ Add step",
|
||||
"routines_addStepTitle": "Add step",
|
||||
"routines_product": "Product",
|
||||
"routines_selectProduct": "Select product",
|
||||
"routines_dose": "Dose",
|
||||
"routines_dosePlaceholder": "e.g. 2 pumps",
|
||||
"routines_region": "Region",
|
||||
"routines_regionPlaceholder": "e.g. face",
|
||||
"routines_addStepBtn": "Add step",
|
||||
"routines_unknownStep": "Unknown step",
|
||||
"routines_noSteps": "No steps yet.",
|
||||
"routines_title": "Routines",
|
||||
"routines_count": "{count} routines (last 30 days)",
|
||||
"routines_suggestAI": "Suggest AI routine",
|
||||
"routines_addNew": "+ New routine",
|
||||
"routines_noRoutines": "No routines found.",
|
||||
"routines_newTitle": "New Routine",
|
||||
"routines_backToList": "← Routines",
|
||||
"routines_detailsTitle": "Routine details",
|
||||
"routines_date": "Date *",
|
||||
"routines_amOrPm": "AM or PM *",
|
||||
"routines_notes": "Notes",
|
||||
"routines_notesPlaceholder": "Optional notes",
|
||||
"routines_createRoutine": "Create routine",
|
||||
"routines_deleteRoutine": "Delete routine",
|
||||
"routines_confirmDelete": "Delete this routine?",
|
||||
"routines_steps": "Steps ({count})",
|
||||
"routines_addStep": "+ Add step",
|
||||
"routines_addStepTitle": "Add step",
|
||||
"routines_product": "Product",
|
||||
"routines_selectProduct": "Select product",
|
||||
"routines_dose": "Dose",
|
||||
"routines_dosePlaceholder": "e.g. 2 pumps",
|
||||
"routines_region": "Region",
|
||||
"routines_regionPlaceholder": "e.g. face",
|
||||
"routines_addStepBtn": "Add step",
|
||||
"routines_unknownStep": "Unknown step",
|
||||
"routines_noSteps": "No steps yet.",
|
||||
|
||||
"grooming_title": "Grooming Schedule",
|
||||
"grooming_backToRoutines": "← Routines",
|
||||
"grooming_addEntry": "+ Add entry",
|
||||
"grooming_entryAdded": "Entry added.",
|
||||
"grooming_entryUpdated": "Entry updated.",
|
||||
"grooming_entryDeleted": "Entry deleted.",
|
||||
"grooming_dayOfWeek": "Day of week",
|
||||
"grooming_action": "Action",
|
||||
"grooming_notesOptional": "Notes (optional)",
|
||||
"grooming_notesPlaceholder": "e.g. every 2 weeks",
|
||||
"grooming_noEntries": "No entries yet. Click \"+ Add entry\" to get started.",
|
||||
"grooming_confirmDelete": "Delete this entry?",
|
||||
"grooming_actionShavingRazor": "Razor shaving",
|
||||
"grooming_actionShavingOneblade": "OneBlade shaving",
|
||||
"grooming_actionDermarolling": "Dermarolling",
|
||||
"grooming_dayMonday": "Monday",
|
||||
"grooming_dayTuesday": "Tuesday",
|
||||
"grooming_dayWednesday": "Wednesday",
|
||||
"grooming_dayThursday": "Thursday",
|
||||
"grooming_dayFriday": "Friday",
|
||||
"grooming_daySaturday": "Saturday",
|
||||
"grooming_daySunday": "Sunday",
|
||||
"grooming_title": "Grooming Schedule",
|
||||
"grooming_backToRoutines": "← Routines",
|
||||
"grooming_addEntry": "+ Add entry",
|
||||
"grooming_entryAdded": "Entry added.",
|
||||
"grooming_entryUpdated": "Entry updated.",
|
||||
"grooming_entryDeleted": "Entry deleted.",
|
||||
"grooming_dayOfWeek": "Day of week",
|
||||
"grooming_action": "Action",
|
||||
"grooming_notesOptional": "Notes (optional)",
|
||||
"grooming_notesPlaceholder": "e.g. every 2 weeks",
|
||||
"grooming_noEntries": "No entries yet. Click \"+ Add entry\" to get started.",
|
||||
"grooming_confirmDelete": "Delete this entry?",
|
||||
"grooming_actionShavingRazor": "Razor shaving",
|
||||
"grooming_actionShavingOneblade": "OneBlade shaving",
|
||||
"grooming_actionDermarolling": "Dermarolling",
|
||||
"grooming_dayMonday": "Monday",
|
||||
"grooming_dayTuesday": "Tuesday",
|
||||
"grooming_dayWednesday": "Wednesday",
|
||||
"grooming_dayThursday": "Thursday",
|
||||
"grooming_dayFriday": "Friday",
|
||||
"grooming_daySaturday": "Saturday",
|
||||
"grooming_daySunday": "Sunday",
|
||||
|
||||
"suggest_title": "AI Routine Suggestion",
|
||||
"suggest_backToRoutines": "← Routines",
|
||||
"suggest_singleTab": "Single routine",
|
||||
"suggest_batchTab": "Batch / Vacation",
|
||||
"suggest_singleParams": "Parameters",
|
||||
"suggest_date": "Date",
|
||||
"suggest_timeOfDay": "Time of day",
|
||||
"suggest_contextLabel": "Additional context for AI",
|
||||
"suggest_contextOptional": "(optional)",
|
||||
"suggest_contextPlaceholder": "e.g. party night, focusing on hydration...",
|
||||
"suggest_leavingHomeLabel": "Going outside today",
|
||||
"suggest_leavingHomeHint": "Affects SPF selection — checked: SPF50+, unchecked: SPF30.",
|
||||
"suggest_minoxidilToggleLabel": "Prioritize beard/mustache density (minoxidil)",
|
||||
"suggest_minoxidilToggleHint": "When enabled, AI will explicitly consider minoxidil for beard/mustache areas if available.",
|
||||
"suggest_generateBtn": "Generate suggestion",
|
||||
"suggest_generating": "Generating…",
|
||||
"suggest_proposalTitle": "Suggestion",
|
||||
"suggest_saveRoutine": "Save routine",
|
||||
"suggest_saving": "Saving…",
|
||||
"suggest_regenerate": "Regenerate",
|
||||
"suggest_batchRange": "Date range",
|
||||
"suggest_fromDate": "From",
|
||||
"suggest_toDate": "To (max 14 days)",
|
||||
"suggest_batchContextLabel": "Context / trip purpose",
|
||||
"suggest_batchContextPlaceholder": "e.g. sunny trip to Italy, active mountain vacation...",
|
||||
"suggest_generatePlan": "Generate plan",
|
||||
"suggest_generatingPlan": "Generating plan…",
|
||||
"suggest_planTitle": "Plan ({count} days)",
|
||||
"suggest_saveAllRoutines": "Save all routines",
|
||||
"suggest_amSteps": "steps",
|
||||
"suggest_pmSteps": "steps",
|
||||
"suggest_noAmSteps": "No AM steps.",
|
||||
"suggest_noPmSteps": "No PM steps.",
|
||||
"suggest_errorDefault": "Error generating suggestion.",
|
||||
"suggest_errorBatch": "Error generating plan.",
|
||||
"suggest_errorSave": "Error saving.",
|
||||
"suggest_amMorning": "AM (morning)",
|
||||
"suggest_pmEvening": "PM (evening)",
|
||||
"suggest_title": "AI Routine Suggestion",
|
||||
"suggest_backToRoutines": "← Routines",
|
||||
"suggest_singleTab": "Single routine",
|
||||
"suggest_batchTab": "Batch / Vacation",
|
||||
"suggest_singleParams": "Parameters",
|
||||
"suggest_date": "Date",
|
||||
"suggest_timeOfDay": "Time of day",
|
||||
"suggest_contextLabel": "Additional context for AI",
|
||||
"suggest_contextOptional": "(optional)",
|
||||
"suggest_contextPlaceholder": "e.g. party night, focusing on hydration...",
|
||||
"suggest_leavingHomeLabel": "Going outside today",
|
||||
"suggest_leavingHomeHint": "Affects SPF selection — checked: SPF50+, unchecked: SPF30.",
|
||||
"suggest_minoxidilToggleLabel": "Prioritize beard/mustache density (minoxidil)",
|
||||
"suggest_minoxidilToggleHint": "When enabled, AI will explicitly consider minoxidil for beard/mustache areas if available.",
|
||||
"suggest_generateBtn": "Generate suggestion",
|
||||
"suggest_generating": "Generating…",
|
||||
"suggest_proposalTitle": "Suggestion",
|
||||
"suggest_saveRoutine": "Save routine",
|
||||
"suggest_saving": "Saving…",
|
||||
"suggest_regenerate": "Regenerate",
|
||||
"suggest_batchRange": "Date range",
|
||||
"suggest_fromDate": "From",
|
||||
"suggest_toDate": "To (max 14 days)",
|
||||
"suggest_batchContextLabel": "Context / trip purpose",
|
||||
"suggest_batchContextPlaceholder": "e.g. sunny trip to Italy, active mountain vacation...",
|
||||
"suggest_generatePlan": "Generate plan",
|
||||
"suggest_generatingPlan": "Generating plan…",
|
||||
"suggest_planTitle": "Plan ({count} days)",
|
||||
"suggest_saveAllRoutines": "Save all routines",
|
||||
"suggest_amSteps": "steps",
|
||||
"suggest_pmSteps": "steps",
|
||||
"suggest_noAmSteps": "No AM steps.",
|
||||
"suggest_noPmSteps": "No PM steps.",
|
||||
"suggest_errorDefault": "Error generating suggestion.",
|
||||
"suggest_errorBatch": "Error generating plan.",
|
||||
"suggest_errorSave": "Error saving.",
|
||||
"suggest_amMorning": "AM (morning)",
|
||||
"suggest_pmEvening": "PM (evening)",
|
||||
|
||||
"medications_title": "Medications",
|
||||
"medications_count": "{count} entries",
|
||||
"medications_addNew": "+ Add medication",
|
||||
"medications_newTitle": "New medication",
|
||||
"medications_kind": "Kind",
|
||||
"medications_productName": "Product name *",
|
||||
"medications_productNamePlaceholder": "e.g. Vitamin D3",
|
||||
"medications_activeSubstance": "Active substance",
|
||||
"medications_activeSubstancePlaceholder": "e.g. cholecalciferol",
|
||||
"medications_notes": "Notes",
|
||||
"medications_added": "Medication added.",
|
||||
"medications_usages": "{count} usages",
|
||||
"medications_noMedications": "No medications recorded.",
|
||||
"medications_kindPrescription": "Prescription",
|
||||
"medications_kindOtc": "OTC",
|
||||
"medications_kindSupplement": "Supplement",
|
||||
"medications_kindHerbal": "Herbal",
|
||||
"medications_kindOther": "Other",
|
||||
"medications_title": "Medications",
|
||||
"medications_count": "{count} entries",
|
||||
"medications_addNew": "+ Add medication",
|
||||
"medications_newTitle": "New medication",
|
||||
"medications_kind": "Kind",
|
||||
"medications_productName": "Product name *",
|
||||
"medications_productNamePlaceholder": "e.g. Vitamin D3",
|
||||
"medications_activeSubstance": "Active substance",
|
||||
"medications_activeSubstancePlaceholder": "e.g. cholecalciferol",
|
||||
"medications_notes": "Notes",
|
||||
"medications_added": "Medication added.",
|
||||
"medications_usages": "{count} usages",
|
||||
"medications_noMedications": "No medications recorded.",
|
||||
"medications_kindPrescription": "Prescription",
|
||||
"medications_kindOtc": "OTC",
|
||||
"medications_kindSupplement": "Supplement",
|
||||
"medications_kindHerbal": "Herbal",
|
||||
"medications_kindOther": "Other",
|
||||
|
||||
"labResults_title": "Lab Results",
|
||||
"labResults_count": "{count} results",
|
||||
"labResults_addNew": "+ Add result",
|
||||
"labResults_newTitle": "New lab result",
|
||||
"labResults_flagFilter": "Flag:",
|
||||
"labResults_flagAll": "All",
|
||||
"labResults_flagNone": "None",
|
||||
"labResults_date": "Date *",
|
||||
"labResults_loincCode": "LOINC code *",
|
||||
"labResults_testName": "Test name",
|
||||
"labResults_testNamePlaceholder": "e.g. Hemoglobin",
|
||||
"labResults_lab": "Lab",
|
||||
"labResults_labPlaceholder": "e.g. LabCorp",
|
||||
"labResults_value": "Value",
|
||||
"labResults_unit": "Unit",
|
||||
"labResults_unitPlaceholder": "e.g. g/dL",
|
||||
"labResults_flag": "Flag",
|
||||
"labResults_added": "Result added.",
|
||||
"labResults_colDate": "Date",
|
||||
"labResults_colTest": "Test",
|
||||
"labResults_colLoinc": "LOINC",
|
||||
"labResults_colValue": "Value",
|
||||
"labResults_colFlag": "Flag",
|
||||
"labResults_colLab": "Lab",
|
||||
"labResults_noResults": "No lab results found.",
|
||||
"labResults_title": "Lab Results",
|
||||
"labResults_count": "{count} results",
|
||||
"labResults_addNew": "+ Add result",
|
||||
"labResults_newTitle": "New lab result",
|
||||
"labResults_flagFilter": "Flag:",
|
||||
"labResults_flagAll": "All",
|
||||
"labResults_flagNone": "None",
|
||||
"labResults_date": "Date *",
|
||||
"labResults_loincCode": "LOINC code *",
|
||||
"labResults_testName": "Test name",
|
||||
"labResults_testNamePlaceholder": "e.g. Hemoglobin",
|
||||
"labResults_lab": "Lab",
|
||||
"labResults_labPlaceholder": "e.g. LabCorp",
|
||||
"labResults_value": "Value",
|
||||
"labResults_unit": "Unit",
|
||||
"labResults_unitPlaceholder": "e.g. g/dL",
|
||||
"labResults_flag": "Flag",
|
||||
"labResults_added": "Result added.",
|
||||
"labResults_colDate": "Date",
|
||||
"labResults_colTest": "Test",
|
||||
"labResults_colLoinc": "LOINC",
|
||||
"labResults_colValue": "Value",
|
||||
"labResults_colFlag": "Flag",
|
||||
"labResults_colLab": "Lab",
|
||||
"labResults_noResults": "No lab results found.",
|
||||
|
||||
"skin_title": "Skin Snapshots",
|
||||
"skin_count": "{count} snapshots",
|
||||
"skin_addNew": "+ Add snapshot",
|
||||
"skin_aiAnalysisTitle": "AI analysis from photos",
|
||||
"skin_aiUploadText": "Upload 1–3 photos of your skin. AI will pre-fill the form fields below.",
|
||||
"skin_analyzePhotos": "Analyze photos",
|
||||
"skin_analyzing": "Analyzing…",
|
||||
"skin_newSnapshotTitle": "New skin snapshot",
|
||||
"skin_date": "Date *",
|
||||
"skin_overallState": "Overall state",
|
||||
"skin_texture": "Texture",
|
||||
"skin_skinType": "Skin type",
|
||||
"skin_barrierState": "Barrier state",
|
||||
"skin_hydration": "Hydration (1–5)",
|
||||
"skin_sensitivity": "Sensitivity (1–5)",
|
||||
"skin_sebumTzone": "Sebum T-zone (1–5)",
|
||||
"skin_sebumCheeks": "Sebum cheeks (1–5)",
|
||||
"skin_activeConcerns": "Active concerns (comma-separated)",
|
||||
"skin_activeConcernsPlaceholder": "acne, redness, dehydration",
|
||||
"skin_priorities": "Priorities (comma-separated)",
|
||||
"skin_prioritiesPlaceholder": "strengthen barrier, reduce redness",
|
||||
"skin_prioritiesLabel": "Priorities",
|
||||
"skin_notes": "Notes",
|
||||
"skin_addSnapshot": "Add snapshot",
|
||||
"skin_snapshotAdded": "Snapshot added.",
|
||||
"skin_snapshotUpdated": "Snapshot updated.",
|
||||
"skin_snapshotDeleted": "Snapshot deleted.",
|
||||
"skin_noSnapshots": "No skin snapshots yet.",
|
||||
"skin_hydrationLabel": "Hydration",
|
||||
"skin_sensitivityLabel": "Sensitivity",
|
||||
"skin_barrierLabel": "Barrier",
|
||||
"skin_stateExcellent": "excellent",
|
||||
"skin_stateGood": "good",
|
||||
"skin_stateFair": "fair",
|
||||
"skin_statePoor": "poor",
|
||||
"skin_textureSmooth": "smooth",
|
||||
"skin_textureRough": "rough",
|
||||
"skin_textureFlaky": "flaky",
|
||||
"skin_textureBumpy": "bumpy",
|
||||
"skin_barrierIntact": "intact",
|
||||
"skin_barrierMildly": "mildly compromised",
|
||||
"skin_barrierCompromised": "compromised",
|
||||
"skin_typeDry": "dry",
|
||||
"skin_typeOily": "oily",
|
||||
"skin_typeCombination": "combination",
|
||||
"skin_typeSensitive": "sensitive",
|
||||
"skin_typeNormal": "normal",
|
||||
"skin_typeAcneProne": "acne prone",
|
||||
"skin_title": "Skin Snapshots",
|
||||
"skin_count": "{count} snapshots",
|
||||
"skin_addNew": "+ Add snapshot",
|
||||
"skin_aiAnalysisTitle": "AI analysis from photos",
|
||||
"skin_aiUploadText": "Upload 1–3 photos of your skin. AI will pre-fill the form fields below.",
|
||||
"skin_analyzePhotos": "Analyze photos",
|
||||
"skin_analyzing": "Analyzing…",
|
||||
"skin_newSnapshotTitle": "New skin snapshot",
|
||||
"skin_date": "Date *",
|
||||
"skin_overallState": "Overall state",
|
||||
"skin_texture": "Texture",
|
||||
"skin_skinType": "Skin type",
|
||||
"skin_barrierState": "Barrier state",
|
||||
"skin_hydration": "Hydration (1–5)",
|
||||
"skin_sensitivity": "Sensitivity (1–5)",
|
||||
"skin_sebumTzone": "Sebum T-zone (1–5)",
|
||||
"skin_sebumCheeks": "Sebum cheeks (1–5)",
|
||||
"skin_activeConcerns": "Active concerns (comma-separated)",
|
||||
"skin_activeConcernsPlaceholder": "acne, redness, dehydration",
|
||||
"skin_priorities": "Priorities (comma-separated)",
|
||||
"skin_prioritiesPlaceholder": "strengthen barrier, reduce redness",
|
||||
"skin_prioritiesLabel": "Priorities",
|
||||
"skin_notes": "Notes",
|
||||
"skin_addSnapshot": "Add snapshot",
|
||||
"skin_snapshotAdded": "Snapshot added.",
|
||||
"skin_snapshotUpdated": "Snapshot updated.",
|
||||
"skin_snapshotDeleted": "Snapshot deleted.",
|
||||
"skin_noSnapshots": "No skin snapshots yet.",
|
||||
"skin_hydrationLabel": "Hydration",
|
||||
"skin_sensitivityLabel": "Sensitivity",
|
||||
"skin_barrierLabel": "Barrier",
|
||||
"skin_stateExcellent": "excellent",
|
||||
"skin_stateGood": "good",
|
||||
"skin_stateFair": "fair",
|
||||
"skin_statePoor": "poor",
|
||||
"skin_textureSmooth": "smooth",
|
||||
"skin_textureRough": "rough",
|
||||
"skin_textureFlaky": "flaky",
|
||||
"skin_textureBumpy": "bumpy",
|
||||
"skin_barrierIntact": "intact",
|
||||
"skin_barrierMildly": "mildly compromised",
|
||||
"skin_barrierCompromised": "compromised",
|
||||
"skin_typeDry": "dry",
|
||||
"skin_typeOily": "oily",
|
||||
"skin_typeCombination": "combination",
|
||||
"skin_typeSensitive": "sensitive",
|
||||
"skin_typeNormal": "normal",
|
||||
"skin_typeAcneProne": "acne prone",
|
||||
|
||||
"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_pasteText": "Paste product description, INCI ingredients here...",
|
||||
"productForm_parseWithAI": "Fill fields (AI)",
|
||||
"productForm_parsing": "Processing…",
|
||||
"productForm_basicInfo": "Basic info",
|
||||
"productForm_name": "Name *",
|
||||
"productForm_namePlaceholder": "e.g. Hydro Boost Water Gel",
|
||||
"productForm_brand": "Brand *",
|
||||
"productForm_brandPlaceholder": "e.g. Neutrogena",
|
||||
"productForm_lineName": "Line / series",
|
||||
"productForm_lineNamePlaceholder": "e.g. Hydro Boost",
|
||||
"productForm_url": "URL",
|
||||
"productForm_sku": "SKU",
|
||||
"productForm_skuPlaceholder": "e.g. NTR-HB-50",
|
||||
"productForm_barcode": "Barcode / EAN",
|
||||
"productForm_barcodePlaceholder": "e.g. 3614273258975",
|
||||
"productForm_classification": "Classification",
|
||||
"productForm_category": "Category *",
|
||||
"productForm_selectCategory": "Select category",
|
||||
"productForm_time": "Time *",
|
||||
"productForm_timeOptions": "AM / PM / Both",
|
||||
"productForm_timeBoth": "Both",
|
||||
"productForm_leaveOn": "Leave-on *",
|
||||
"productForm_leaveOnYes": "Yes (leave-on)",
|
||||
"productForm_leaveOnNo": "No (rinse-off)",
|
||||
"productForm_texture": "Texture",
|
||||
"productForm_selectTexture": "Select texture",
|
||||
"productForm_absorptionSpeed": "Absorption speed",
|
||||
"productForm_selectSpeed": "Select speed",
|
||||
"productForm_skinProfile": "Skin profile",
|
||||
"productForm_recommendedFor": "Recommended for skin types",
|
||||
"productForm_targetConcerns": "Target concerns",
|
||||
"productForm_contraindications": "Contraindications (one per line)",
|
||||
"productForm_contraindicationsPlaceholder": "e.g. active rosacea flares",
|
||||
"productForm_ingredients": "Ingredients",
|
||||
"productForm_inciList": "INCI list (one ingredient per line)",
|
||||
"productForm_activeIngredients": "Active ingredients",
|
||||
"productForm_addActive": "+ Add active",
|
||||
"productForm_noActives": "No actives added yet.",
|
||||
"productForm_activeName": "Name",
|
||||
"productForm_activePercent": "%",
|
||||
"productForm_activeStrength": "Strength",
|
||||
"productForm_activeIrritation": "Irritation",
|
||||
"productForm_activeFunctions": "Functions",
|
||||
"productForm_effectProfile": "Effect profile (0–5)",
|
||||
"productForm_interactions": "Interactions",
|
||||
"productForm_synergizesWith": "Synergizes with (one per line)",
|
||||
"productForm_incompatibleWith": "Incompatible with",
|
||||
"productForm_addIncompatibility": "+ Add incompatibility",
|
||||
"productForm_noIncompatibilities": "No incompatibilities added.",
|
||||
"productForm_incompTarget": "Target ingredient",
|
||||
"productForm_incompScope": "Scope",
|
||||
"productForm_incompReason": "Reason (optional)",
|
||||
"productForm_incompReasonPlaceholder": "e.g. reduces efficacy",
|
||||
"productForm_incompScopeSelect": "Select…",
|
||||
"productForm_contextRules": "Context rules",
|
||||
"productForm_ctxAfterShaving": "Safe after shaving",
|
||||
"productForm_ctxAfterAcids": "Safe after acids",
|
||||
"productForm_ctxAfterRetinoids": "Safe after retinoids",
|
||||
"productForm_ctxCompromisedBarrier": "Safe with compromised barrier",
|
||||
"productForm_ctxLowUvOnly": "Low UV only (evening/covered)",
|
||||
"productForm_productDetails": "Product details",
|
||||
"productForm_priceTier": "Price tier",
|
||||
"productForm_selectTier": "Select tier",
|
||||
"productForm_sizeMl": "Size (ml)",
|
||||
"productForm_fullWeightG": "Full weight (g)",
|
||||
"productForm_emptyWeightG": "Empty weight (g)",
|
||||
"productForm_paoMonths": "PAO (months)",
|
||||
"productForm_phMin": "pH min",
|
||||
"productForm_phMax": "pH max",
|
||||
"productForm_usageNotes": "Usage notes",
|
||||
"productForm_usageNotesPlaceholder": "e.g. Apply to damp skin, avoid eye area",
|
||||
"productForm_safetyFlags": "Safety flags",
|
||||
"productForm_fragranceFree": "Fragrance-free",
|
||||
"productForm_essentialOilsFree": "Essential oils-free",
|
||||
"productForm_alcoholDenatFree": "Alcohol denat-free",
|
||||
"productForm_pregnancySafe": "Pregnancy safe",
|
||||
"productForm_usageConstraints": "Usage constraints",
|
||||
"productForm_minIntervalHours": "Min interval (hours)",
|
||||
"productForm_maxFrequencyPerWeek": "Max uses per week",
|
||||
"productForm_isMedication": "Is medication",
|
||||
"productForm_isTool": "Is tool (e.g. dermaroller)",
|
||||
"productForm_needleLengthMm": "Needle length (mm, tools only)",
|
||||
"productForm_personalNotes": "Personal notes",
|
||||
"productForm_repurchaseIntent": "Repurchase intent",
|
||||
"productForm_toleranceNotes": "Tolerance notes",
|
||||
"productForm_toleranceNotesPlaceholder": "e.g. Causes mild stinging, fine after 2 weeks",
|
||||
"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_pasteText": "Paste product description, INCI ingredients here...",
|
||||
"productForm_parseWithAI": "Fill fields (AI)",
|
||||
"productForm_parsing": "Processing…",
|
||||
"productForm_basicInfo": "Basic info",
|
||||
"productForm_name": "Name *",
|
||||
"productForm_namePlaceholder": "e.g. Hydro Boost Water Gel",
|
||||
"productForm_brand": "Brand *",
|
||||
"productForm_brandPlaceholder": "e.g. Neutrogena",
|
||||
"productForm_lineName": "Line / series",
|
||||
"productForm_lineNamePlaceholder": "e.g. Hydro Boost",
|
||||
"productForm_url": "URL",
|
||||
"productForm_sku": "SKU",
|
||||
"productForm_skuPlaceholder": "e.g. NTR-HB-50",
|
||||
"productForm_barcode": "Barcode / EAN",
|
||||
"productForm_barcodePlaceholder": "e.g. 3614273258975",
|
||||
"productForm_classification": "Classification",
|
||||
"productForm_category": "Category *",
|
||||
"productForm_selectCategory": "Select category",
|
||||
"productForm_time": "Time *",
|
||||
"productForm_timeOptions": "AM / PM / Both",
|
||||
"productForm_timeBoth": "Both",
|
||||
"productForm_leaveOn": "Leave-on *",
|
||||
"productForm_leaveOnYes": "Yes (leave-on)",
|
||||
"productForm_leaveOnNo": "No (rinse-off)",
|
||||
"productForm_texture": "Texture",
|
||||
"productForm_selectTexture": "Select texture",
|
||||
"productForm_absorptionSpeed": "Absorption speed",
|
||||
"productForm_selectSpeed": "Select speed",
|
||||
"productForm_skinProfile": "Skin profile",
|
||||
"productForm_recommendedFor": "Recommended for skin types",
|
||||
"productForm_targetConcerns": "Target concerns",
|
||||
"productForm_contraindications": "Contraindications (one per line)",
|
||||
"productForm_contraindicationsPlaceholder": "e.g. active rosacea flares",
|
||||
"productForm_ingredients": "Ingredients",
|
||||
"productForm_inciList": "INCI list (one ingredient per line)",
|
||||
"productForm_activeIngredients": "Active ingredients",
|
||||
"productForm_addActive": "+ Add active",
|
||||
"productForm_noActives": "No actives added yet.",
|
||||
"productForm_activeName": "Name",
|
||||
"productForm_activePercent": "%",
|
||||
"productForm_activeStrength": "Strength",
|
||||
"productForm_activeIrritation": "Irritation",
|
||||
"productForm_activeFunctions": "Functions",
|
||||
"productForm_effectProfile": "Effect profile (0–5)",
|
||||
"productForm_interactions": "Interactions",
|
||||
"productForm_synergizesWith": "Synergizes with (one per line)",
|
||||
"productForm_incompatibleWith": "Incompatible with",
|
||||
"productForm_addIncompatibility": "+ Add incompatibility",
|
||||
"productForm_noIncompatibilities": "No incompatibilities added.",
|
||||
"productForm_incompTarget": "Target ingredient",
|
||||
"productForm_incompScope": "Scope",
|
||||
"productForm_incompReason": "Reason (optional)",
|
||||
"productForm_incompReasonPlaceholder": "e.g. reduces efficacy",
|
||||
"productForm_incompScopeSelect": "Select…",
|
||||
"productForm_contextRules": "Context rules",
|
||||
"productForm_ctxAfterShaving": "Safe after shaving",
|
||||
"productForm_ctxAfterAcids": "Safe after acids",
|
||||
"productForm_ctxAfterRetinoids": "Safe after retinoids",
|
||||
"productForm_ctxCompromisedBarrier": "Safe with compromised barrier",
|
||||
"productForm_ctxLowUvOnly": "Low UV only (evening/covered)",
|
||||
"productForm_productDetails": "Product details",
|
||||
"productForm_priceTier": "Price tier",
|
||||
"productForm_selectTier": "Select tier",
|
||||
"productForm_sizeMl": "Size (ml)",
|
||||
"productForm_fullWeightG": "Full weight (g)",
|
||||
"productForm_emptyWeightG": "Empty weight (g)",
|
||||
"productForm_paoMonths": "PAO (months)",
|
||||
"productForm_phMin": "pH min",
|
||||
"productForm_phMax": "pH max",
|
||||
"productForm_usageNotes": "Usage notes",
|
||||
"productForm_usageNotesPlaceholder": "e.g. Apply to damp skin, avoid eye area",
|
||||
"productForm_safetyFlags": "Safety flags",
|
||||
"productForm_fragranceFree": "Fragrance-free",
|
||||
"productForm_essentialOilsFree": "Essential oils-free",
|
||||
"productForm_alcoholDenatFree": "Alcohol denat-free",
|
||||
"productForm_pregnancySafe": "Pregnancy safe",
|
||||
"productForm_usageConstraints": "Usage constraints",
|
||||
"productForm_minIntervalHours": "Min interval (hours)",
|
||||
"productForm_maxFrequencyPerWeek": "Max uses per week",
|
||||
"productForm_isMedication": "Is medication",
|
||||
"productForm_isTool": "Is tool (e.g. dermaroller)",
|
||||
"productForm_needleLengthMm": "Needle length (mm, tools only)",
|
||||
"productForm_personalNotes": "Personal notes",
|
||||
"productForm_repurchaseIntent": "Repurchase intent",
|
||||
"productForm_toleranceNotes": "Tolerance notes",
|
||||
"productForm_toleranceNotesPlaceholder": "e.g. Causes mild stinging, fine after 2 weeks",
|
||||
|
||||
"productForm_categoryCleanser": "Cleanser",
|
||||
"productForm_categoryToner": "Toner",
|
||||
"productForm_categoryEssence": "Essence",
|
||||
"productForm_categorySerum": "Serum",
|
||||
"productForm_categoryMoisturizer": "Moisturizer",
|
||||
"productForm_categorySpf": "SPF",
|
||||
"productForm_categoryMask": "Mask",
|
||||
"productForm_categoryExfoliant": "Exfoliant",
|
||||
"productForm_categoryHairTreatment": "Hair treatment",
|
||||
"productForm_categoryTool": "Tool",
|
||||
"productForm_categorySpotTreatment": "Spot treatment",
|
||||
"productForm_categoryOil": "Oil",
|
||||
"productForm_categoryCleanser": "Cleanser",
|
||||
"productForm_categoryToner": "Toner",
|
||||
"productForm_categoryEssence": "Essence",
|
||||
"productForm_categorySerum": "Serum",
|
||||
"productForm_categoryMoisturizer": "Moisturizer",
|
||||
"productForm_categorySpf": "SPF",
|
||||
"productForm_categoryMask": "Mask",
|
||||
"productForm_categoryExfoliant": "Exfoliant",
|
||||
"productForm_categoryHairTreatment": "Hair treatment",
|
||||
"productForm_categoryTool": "Tool",
|
||||
"productForm_categorySpotTreatment": "Spot treatment",
|
||||
"productForm_categoryOil": "Oil",
|
||||
|
||||
"productForm_textureWatery": "Watery",
|
||||
"productForm_textureGel": "Gel",
|
||||
"productForm_textureEmulsion": "Emulsion",
|
||||
"productForm_textureCream": "Cream",
|
||||
"productForm_textureOil": "Oil",
|
||||
"productForm_textureBalm": "Balm",
|
||||
"productForm_textureFoam": "Foam",
|
||||
"productForm_textureFluid": "Fluid",
|
||||
"productForm_textureWatery": "Watery",
|
||||
"productForm_textureGel": "Gel",
|
||||
"productForm_textureEmulsion": "Emulsion",
|
||||
"productForm_textureCream": "Cream",
|
||||
"productForm_textureOil": "Oil",
|
||||
"productForm_textureBalm": "Balm",
|
||||
"productForm_textureFoam": "Foam",
|
||||
"productForm_textureFluid": "Fluid",
|
||||
|
||||
"productForm_absorptionVeryFast": "Very fast",
|
||||
"productForm_absorptionFast": "Fast",
|
||||
"productForm_absorptionModerate": "Moderate",
|
||||
"productForm_absorptionSlow": "Slow",
|
||||
"productForm_absorptionVerySlow": "Very slow",
|
||||
"productForm_absorptionVeryFast": "Very fast",
|
||||
"productForm_absorptionFast": "Fast",
|
||||
"productForm_absorptionModerate": "Moderate",
|
||||
"productForm_absorptionSlow": "Slow",
|
||||
"productForm_absorptionVerySlow": "Very slow",
|
||||
|
||||
"productForm_priceBudget": "Budget",
|
||||
"productForm_priceMid": "Mid",
|
||||
"productForm_pricePremium": "Premium",
|
||||
"productForm_priceLuxury": "Luxury",
|
||||
"productForm_priceBudget": "Budget",
|
||||
"productForm_priceMid": "Mid",
|
||||
"productForm_pricePremium": "Premium",
|
||||
"productForm_priceLuxury": "Luxury",
|
||||
|
||||
"productForm_skinTypeDry": "dry",
|
||||
"productForm_skinTypeOily": "oily",
|
||||
"productForm_skinTypeCombination": "combination",
|
||||
"productForm_skinTypeSensitive": "sensitive",
|
||||
"productForm_skinTypeNormal": "normal",
|
||||
"productForm_skinTypeAcneProne": "acne prone",
|
||||
"productForm_skinTypeDry": "dry",
|
||||
"productForm_skinTypeOily": "oily",
|
||||
"productForm_skinTypeCombination": "combination",
|
||||
"productForm_skinTypeSensitive": "sensitive",
|
||||
"productForm_skinTypeNormal": "normal",
|
||||
"productForm_skinTypeAcneProne": "acne prone",
|
||||
|
||||
"productForm_concernAcne": "acne",
|
||||
"productForm_concernRosacea": "rosacea",
|
||||
"productForm_concernHyperpigmentation": "hyperpigmentation",
|
||||
"productForm_concernAging": "aging",
|
||||
"productForm_concernDehydration": "dehydration",
|
||||
"productForm_concernRedness": "redness",
|
||||
"productForm_concernDamagedBarrier": "damaged barrier",
|
||||
"productForm_concernPoreVisibility": "pore visibility",
|
||||
"productForm_concernUnevenTexture": "uneven texture",
|
||||
"productForm_concernHairGrowth": "hair growth",
|
||||
"productForm_concernSebumExcess": "sebum excess",
|
||||
"productForm_concernAcne": "acne",
|
||||
"productForm_concernRosacea": "rosacea",
|
||||
"productForm_concernHyperpigmentation": "hyperpigmentation",
|
||||
"productForm_concernAging": "aging",
|
||||
"productForm_concernDehydration": "dehydration",
|
||||
"productForm_concernRedness": "redness",
|
||||
"productForm_concernDamagedBarrier": "damaged barrier",
|
||||
"productForm_concernPoreVisibility": "pore visibility",
|
||||
"productForm_concernUnevenTexture": "uneven texture",
|
||||
"productForm_concernHairGrowth": "hair growth",
|
||||
"productForm_concernSebumExcess": "sebum excess",
|
||||
|
||||
"productForm_fnHumectant": "humectant",
|
||||
"productForm_fnEmollient": "emollient",
|
||||
"productForm_fnOcclusive": "occlusive",
|
||||
"productForm_fnExfoliantAha": "AHA exfoliant",
|
||||
"productForm_fnExfoliantBha": "BHA exfoliant",
|
||||
"productForm_fnExfoliantPha": "PHA exfoliant",
|
||||
"productForm_fnRetinoid": "retinoid",
|
||||
"productForm_fnAntioxidant": "antioxidant",
|
||||
"productForm_fnSoothing": "soothing",
|
||||
"productForm_fnBarrierSupport": "barrier support",
|
||||
"productForm_fnBrightening": "brightening",
|
||||
"productForm_fnAntiAcne": "anti-acne",
|
||||
"productForm_fnCeramide": "ceramide",
|
||||
"productForm_fnNiacinamide": "niacinamide",
|
||||
"productForm_fnSunscreen": "sunscreen",
|
||||
"productForm_fnPeptide": "peptide",
|
||||
"productForm_fnHairGrowth": "hair growth stimulant",
|
||||
"productForm_fnPrebiotic": "prebiotic",
|
||||
"productForm_fnVitaminC": "vitamin C",
|
||||
"productForm_fnAntiAging": "anti-aging",
|
||||
"productForm_fnHumectant": "humectant",
|
||||
"productForm_fnEmollient": "emollient",
|
||||
"productForm_fnOcclusive": "occlusive",
|
||||
"productForm_fnExfoliantAha": "AHA exfoliant",
|
||||
"productForm_fnExfoliantBha": "BHA exfoliant",
|
||||
"productForm_fnExfoliantPha": "PHA exfoliant",
|
||||
"productForm_fnRetinoid": "retinoid",
|
||||
"productForm_fnAntioxidant": "antioxidant",
|
||||
"productForm_fnSoothing": "soothing",
|
||||
"productForm_fnBarrierSupport": "barrier support",
|
||||
"productForm_fnBrightening": "brightening",
|
||||
"productForm_fnAntiAcne": "anti-acne",
|
||||
"productForm_fnCeramide": "ceramide",
|
||||
"productForm_fnNiacinamide": "niacinamide",
|
||||
"productForm_fnSunscreen": "sunscreen",
|
||||
"productForm_fnPeptide": "peptide",
|
||||
"productForm_fnHairGrowth": "hair growth stimulant",
|
||||
"productForm_fnPrebiotic": "prebiotic",
|
||||
"productForm_fnVitaminC": "vitamin C",
|
||||
"productForm_fnAntiAging": "anti-aging",
|
||||
|
||||
"productForm_scopeSameStep": "same step",
|
||||
"productForm_scopeSameDay": "same day",
|
||||
"productForm_scopeSamePeriod": "same period",
|
||||
"productForm_scopeSameStep": "same step",
|
||||
"productForm_scopeSameDay": "same day",
|
||||
"productForm_scopeSamePeriod": "same period",
|
||||
|
||||
"productForm_strengthLow": "1 Low",
|
||||
"productForm_strengthMedium": "2 Medium",
|
||||
"productForm_strengthHigh": "3 High",
|
||||
"productForm_strengthLow": "1 Low",
|
||||
"productForm_strengthMedium": "2 Medium",
|
||||
"productForm_strengthHigh": "3 High",
|
||||
|
||||
"productForm_effectHydrationImmediate": "Hydration (immediate)",
|
||||
"productForm_effectHydrationLongTerm": "Hydration (long term)",
|
||||
"productForm_effectBarrierRepair": "Barrier repair",
|
||||
"productForm_effectSoothing": "Soothing",
|
||||
"productForm_effectExfoliation": "Exfoliation",
|
||||
"productForm_effectRetinoid": "Retinoid activity",
|
||||
"productForm_effectIrritation": "Irritation risk",
|
||||
"productForm_effectComedogenic": "Comedogenic risk",
|
||||
"productForm_effectBarrierDisruption": "Barrier disruption risk",
|
||||
"productForm_effectDryness": "Dryness risk",
|
||||
"productForm_effectBrightening": "Brightening",
|
||||
"productForm_effectAntiAcne": "Anti-acne",
|
||||
"productForm_effectAntiAging": "Anti-aging",
|
||||
"productForm_effectHydrationImmediate": "Hydration (immediate)",
|
||||
"productForm_effectHydrationLongTerm": "Hydration (long term)",
|
||||
"productForm_effectBarrierRepair": "Barrier repair",
|
||||
"productForm_effectSoothing": "Soothing",
|
||||
"productForm_effectExfoliation": "Exfoliation",
|
||||
"productForm_effectRetinoid": "Retinoid activity",
|
||||
"productForm_effectIrritation": "Irritation risk",
|
||||
"productForm_effectComedogenic": "Comedogenic risk",
|
||||
"productForm_effectBarrierDisruption": "Barrier disruption risk",
|
||||
"productForm_effectDryness": "Dryness risk",
|
||||
"productForm_effectBrightening": "Brightening",
|
||||
"productForm_effectAntiAcne": "Anti-acne",
|
||||
"productForm_effectAntiAging": "Anti-aging",
|
||||
|
||||
"lang_pl": "PL",
|
||||
"lang_en": "EN"
|
||||
"lang_pl": "PL",
|
||||
"lang_en": "EN"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,455 +1,455 @@
|
|||
{
|
||||
"nav_dashboard": "Dashboard",
|
||||
"nav_products": "Produkty",
|
||||
"nav_routines": "Rutyny",
|
||||
"nav_grooming": "Pielęgnacja",
|
||||
"nav_medications": "Leki",
|
||||
"nav_labResults": "Wyniki badań",
|
||||
"nav_skin": "Skóra",
|
||||
"nav_appName": "innercontext",
|
||||
"nav_appSubtitle": "zdrowie & pielęgnacja",
|
||||
"nav_dashboard": "Dashboard",
|
||||
"nav_products": "Produkty",
|
||||
"nav_routines": "Rutyny",
|
||||
"nav_grooming": "Pielęgnacja",
|
||||
"nav_medications": "Leki",
|
||||
"nav_labResults": "Wyniki badań",
|
||||
"nav_skin": "Skóra",
|
||||
"nav_appName": "innercontext",
|
||||
"nav_appSubtitle": "zdrowie & pielęgnacja",
|
||||
|
||||
"common_save": "Zapisz",
|
||||
"common_cancel": "Anuluj",
|
||||
"common_add": "Dodaj",
|
||||
"common_edit": "Edytuj",
|
||||
"common_delete": "Usuń",
|
||||
"common_saved": "Zapisano.",
|
||||
"common_select": "Wybierz",
|
||||
"common_unknown": "Nieznane",
|
||||
"common_yes": "Tak",
|
||||
"common_no": "Nie",
|
||||
"common_unknown_value": "Nieznane",
|
||||
"common_optional_notes": "opcjonalnie",
|
||||
"common_steps": "kroków",
|
||||
"common_save": "Zapisz",
|
||||
"common_cancel": "Anuluj",
|
||||
"common_add": "Dodaj",
|
||||
"common_edit": "Edytuj",
|
||||
"common_delete": "Usuń",
|
||||
"common_saved": "Zapisano.",
|
||||
"common_select": "Wybierz",
|
||||
"common_unknown": "Nieznane",
|
||||
"common_yes": "Tak",
|
||||
"common_no": "Nie",
|
||||
"common_unknown_value": "Nieznane",
|
||||
"common_optional_notes": "opcjonalnie",
|
||||
"common_steps": "kroków",
|
||||
|
||||
"dashboard_title": "Dashboard",
|
||||
"dashboard_subtitle": "Przegląd zdrowia i pielęgnacji",
|
||||
"dashboard_latestSnapshot": "Ostatni stan skóry",
|
||||
"dashboard_recentRoutines": "Ostatnie rutyny",
|
||||
"dashboard_noSnapshots": "Brak wpisów o stanie skóry.",
|
||||
"dashboard_noRoutines": "Brak rutyno w ciągu ostatnich 2 tygodni.",
|
||||
"dashboard_title": "Dashboard",
|
||||
"dashboard_subtitle": "Przegląd zdrowia i pielęgnacji",
|
||||
"dashboard_latestSnapshot": "Ostatni stan skóry",
|
||||
"dashboard_recentRoutines": "Ostatnie rutyny",
|
||||
"dashboard_noSnapshots": "Brak wpisów o stanie skóry.",
|
||||
"dashboard_noRoutines": "Brak rutyno w ciągu ostatnich 2 tygodni.",
|
||||
|
||||
"products_title": "Produkty",
|
||||
"products_count": "{count} produktów",
|
||||
"products_addNew": "+ Dodaj produkt",
|
||||
"products_suggest": "Sugeruj",
|
||||
"products_suggestTitle": "Sugestie zakupowe",
|
||||
"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_suggestGenerating": "Analizuję...",
|
||||
"products_suggestBtn": "Generuj sugestie",
|
||||
"products_suggestResults": "Propozycje",
|
||||
"products_suggestTime": "Pora",
|
||||
"products_suggestFrequency": "Częstotliwość",
|
||||
"products_suggestRegenerate": "Wygeneruj ponownie",
|
||||
"products_suggestNoResults": "Brak propozycji.",
|
||||
"products_noProducts": "Nie znaleziono produktów.",
|
||||
"products_filterAll": "Wszystkie",
|
||||
"products_filterOwned": "Posiadane",
|
||||
"products_filterUnowned": "Nieposiadane",
|
||||
"products_colName": "Nazwa",
|
||||
"products_colBrand": "Marka",
|
||||
"products_colTargets": "Cele",
|
||||
"products_colTime": "Pora",
|
||||
"products_newTitle": "Nowy produkt",
|
||||
"products_backToList": "← Produkty",
|
||||
"products_createProduct": "Utwórz produkt",
|
||||
"products_saveChanges": "Zapisz zmiany",
|
||||
"products_deleteProduct": "Usuń produkt",
|
||||
"products_confirmDelete": "Usunąć ten produkt?",
|
||||
"products_noInventory": "Brak opakowań w magazynie.",
|
||||
"products_title": "Produkty",
|
||||
"products_count": "{count} produktów",
|
||||
"products_addNew": "+ Dodaj produkt",
|
||||
"products_suggest": "Sugeruj",
|
||||
"products_suggestTitle": "Sugestie zakupowe",
|
||||
"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_suggestGenerating": "Analizuję...",
|
||||
"products_suggestBtn": "Generuj sugestie",
|
||||
"products_suggestResults": "Propozycje",
|
||||
"products_suggestTime": "Pora",
|
||||
"products_suggestFrequency": "Częstotliwość",
|
||||
"products_suggestRegenerate": "Wygeneruj ponownie",
|
||||
"products_suggestNoResults": "Brak propozycji.",
|
||||
"products_noProducts": "Nie znaleziono produktów.",
|
||||
"products_filterAll": "Wszystkie",
|
||||
"products_filterOwned": "Posiadane",
|
||||
"products_filterUnowned": "Nieposiadane",
|
||||
"products_colName": "Nazwa",
|
||||
"products_colBrand": "Marka",
|
||||
"products_colTargets": "Cele",
|
||||
"products_colTime": "Pora",
|
||||
"products_newTitle": "Nowy produkt",
|
||||
"products_backToList": "← Produkty",
|
||||
"products_createProduct": "Utwórz produkt",
|
||||
"products_saveChanges": "Zapisz zmiany",
|
||||
"products_deleteProduct": "Usuń produkt",
|
||||
"products_confirmDelete": "Usunąć ten produkt?",
|
||||
"products_noInventory": "Brak opakowań w magazynie.",
|
||||
|
||||
"inventory_title": "Opakowania ({count})",
|
||||
"inventory_addPackage": "+ Dodaj opakowanie",
|
||||
"inventory_packageAdded": "Opakowanie dodane.",
|
||||
"inventory_packageUpdated": "Opakowanie zaktualizowane.",
|
||||
"inventory_packageDeleted": "Opakowanie usunięte.",
|
||||
"inventory_alreadyOpened": "Już otwarte",
|
||||
"inventory_openedDate": "Data otwarcia",
|
||||
"inventory_finishedDate": "Data skończenia",
|
||||
"inventory_expiryDate": "Data ważności",
|
||||
"inventory_currentWeight": "Aktualna waga (g)",
|
||||
"inventory_lastWeighed": "Ostatnie ważenie",
|
||||
"inventory_notes": "Notatki",
|
||||
"inventory_badgeOpen": "Otwarte",
|
||||
"inventory_badgeSealed": "Zamknięte",
|
||||
"inventory_badgeFinished": "Skończone",
|
||||
"inventory_exp": "Wazność:",
|
||||
"inventory_opened": "Otwarto:",
|
||||
"inventory_finished": "Skończono:",
|
||||
"inventory_remaining": "g pozostało",
|
||||
"inventory_weighed": "Ważono:",
|
||||
"inventory_confirmDelete": "Usunąć to opakowanie?",
|
||||
"inventory_title": "Opakowania ({count})",
|
||||
"inventory_addPackage": "+ Dodaj opakowanie",
|
||||
"inventory_packageAdded": "Opakowanie dodane.",
|
||||
"inventory_packageUpdated": "Opakowanie zaktualizowane.",
|
||||
"inventory_packageDeleted": "Opakowanie usunięte.",
|
||||
"inventory_alreadyOpened": "Już otwarte",
|
||||
"inventory_openedDate": "Data otwarcia",
|
||||
"inventory_finishedDate": "Data skończenia",
|
||||
"inventory_expiryDate": "Data ważności",
|
||||
"inventory_currentWeight": "Aktualna waga (g)",
|
||||
"inventory_lastWeighed": "Ostatnie ważenie",
|
||||
"inventory_notes": "Notatki",
|
||||
"inventory_badgeOpen": "Otwarte",
|
||||
"inventory_badgeSealed": "Zamknięte",
|
||||
"inventory_badgeFinished": "Skończone",
|
||||
"inventory_exp": "Wazność:",
|
||||
"inventory_opened": "Otwarto:",
|
||||
"inventory_finished": "Skończono:",
|
||||
"inventory_remaining": "g pozostało",
|
||||
"inventory_weighed": "Ważono:",
|
||||
"inventory_confirmDelete": "Usunąć to opakowanie?",
|
||||
|
||||
"routines_title": "Rutyny",
|
||||
"routines_count": "{count} rutyno (ostatnie 30 dni)",
|
||||
"routines_suggestAI": "Zaproponuj rutynę AI",
|
||||
"routines_addNew": "+ Nowa rutyna",
|
||||
"routines_noRoutines": "Nie znaleziono rutyno.",
|
||||
"routines_newTitle": "Nowa rutyna",
|
||||
"routines_backToList": "← Rutyny",
|
||||
"routines_detailsTitle": "Szczegóły rutyny",
|
||||
"routines_date": "Data *",
|
||||
"routines_amOrPm": "AM lub PM *",
|
||||
"routines_notes": "Notatki",
|
||||
"routines_notesPlaceholder": "Opcjonalne notatki",
|
||||
"routines_createRoutine": "Utwórz rutynę",
|
||||
"routines_deleteRoutine": "Usuń rutynę",
|
||||
"routines_confirmDelete": "Usunąć tę rutynę?",
|
||||
"routines_steps": "Kroki ({count})",
|
||||
"routines_addStep": "+ Dodaj krok",
|
||||
"routines_addStepTitle": "Dodaj krok",
|
||||
"routines_product": "Produkt",
|
||||
"routines_selectProduct": "Wybierz produkt",
|
||||
"routines_dose": "Dawka",
|
||||
"routines_dosePlaceholder": "np. 2 pompki",
|
||||
"routines_region": "Okolica",
|
||||
"routines_regionPlaceholder": "np. twarz",
|
||||
"routines_addStepBtn": "Dodaj krok",
|
||||
"routines_unknownStep": "Nieznany krok",
|
||||
"routines_noSteps": "Brak kroków.",
|
||||
"routines_title": "Rutyny",
|
||||
"routines_count": "{count} rutyno (ostatnie 30 dni)",
|
||||
"routines_suggestAI": "Zaproponuj rutynę AI",
|
||||
"routines_addNew": "+ Nowa rutyna",
|
||||
"routines_noRoutines": "Nie znaleziono rutyno.",
|
||||
"routines_newTitle": "Nowa rutyna",
|
||||
"routines_backToList": "← Rutyny",
|
||||
"routines_detailsTitle": "Szczegóły rutyny",
|
||||
"routines_date": "Data *",
|
||||
"routines_amOrPm": "AM lub PM *",
|
||||
"routines_notes": "Notatki",
|
||||
"routines_notesPlaceholder": "Opcjonalne notatki",
|
||||
"routines_createRoutine": "Utwórz rutynę",
|
||||
"routines_deleteRoutine": "Usuń rutynę",
|
||||
"routines_confirmDelete": "Usunąć tę rutynę?",
|
||||
"routines_steps": "Kroki ({count})",
|
||||
"routines_addStep": "+ Dodaj krok",
|
||||
"routines_addStepTitle": "Dodaj krok",
|
||||
"routines_product": "Produkt",
|
||||
"routines_selectProduct": "Wybierz produkt",
|
||||
"routines_dose": "Dawka",
|
||||
"routines_dosePlaceholder": "np. 2 pompki",
|
||||
"routines_region": "Okolica",
|
||||
"routines_regionPlaceholder": "np. twarz",
|
||||
"routines_addStepBtn": "Dodaj krok",
|
||||
"routines_unknownStep": "Nieznany krok",
|
||||
"routines_noSteps": "Brak kroków.",
|
||||
|
||||
"grooming_title": "Harmonogram pielęgnacji",
|
||||
"grooming_backToRoutines": "← Rutyny",
|
||||
"grooming_addEntry": "+ Dodaj wpis",
|
||||
"grooming_entryAdded": "Wpis dodany.",
|
||||
"grooming_entryUpdated": "Wpis zaktualizowany.",
|
||||
"grooming_entryDeleted": "Wpis usunięty.",
|
||||
"grooming_dayOfWeek": "Dzień tygodnia",
|
||||
"grooming_action": "Czynność",
|
||||
"grooming_notesOptional": "Notatki (opcjonalnie)",
|
||||
"grooming_notesPlaceholder": "np. co 2 tygodnie",
|
||||
"grooming_noEntries": "Brak wpisów. Kliknij \"+ Dodaj wpis\", aby zacząć.",
|
||||
"grooming_confirmDelete": "Usunąć ten wpis?",
|
||||
"grooming_actionShavingRazor": "Golenie maszynką",
|
||||
"grooming_actionShavingOneblade": "Golenie OneBlade",
|
||||
"grooming_actionDermarolling": "Dermarolling",
|
||||
"grooming_dayMonday": "Poniedziałek",
|
||||
"grooming_dayTuesday": "Wtorek",
|
||||
"grooming_dayWednesday": "Środa",
|
||||
"grooming_dayThursday": "Czwartek",
|
||||
"grooming_dayFriday": "Piątek",
|
||||
"grooming_daySaturday": "Sobota",
|
||||
"grooming_daySunday": "Niedziela",
|
||||
"grooming_title": "Harmonogram pielęgnacji",
|
||||
"grooming_backToRoutines": "← Rutyny",
|
||||
"grooming_addEntry": "+ Dodaj wpis",
|
||||
"grooming_entryAdded": "Wpis dodany.",
|
||||
"grooming_entryUpdated": "Wpis zaktualizowany.",
|
||||
"grooming_entryDeleted": "Wpis usunięty.",
|
||||
"grooming_dayOfWeek": "Dzień tygodnia",
|
||||
"grooming_action": "Czynność",
|
||||
"grooming_notesOptional": "Notatki (opcjonalnie)",
|
||||
"grooming_notesPlaceholder": "np. co 2 tygodnie",
|
||||
"grooming_noEntries": "Brak wpisów. Kliknij \"+ Dodaj wpis\", aby zacząć.",
|
||||
"grooming_confirmDelete": "Usunąć ten wpis?",
|
||||
"grooming_actionShavingRazor": "Golenie maszynką",
|
||||
"grooming_actionShavingOneblade": "Golenie OneBlade",
|
||||
"grooming_actionDermarolling": "Dermarolling",
|
||||
"grooming_dayMonday": "Poniedziałek",
|
||||
"grooming_dayTuesday": "Wtorek",
|
||||
"grooming_dayWednesday": "Środa",
|
||||
"grooming_dayThursday": "Czwartek",
|
||||
"grooming_dayFriday": "Piątek",
|
||||
"grooming_daySaturday": "Sobota",
|
||||
"grooming_daySunday": "Niedziela",
|
||||
|
||||
"suggest_title": "Propozycja rutyny AI",
|
||||
"suggest_backToRoutines": "← Rutyny",
|
||||
"suggest_singleTab": "Jedna rutyna",
|
||||
"suggest_batchTab": "Batch / Urlop",
|
||||
"suggest_singleParams": "Parametry",
|
||||
"suggest_date": "Data",
|
||||
"suggest_timeOfDay": "Pora dnia",
|
||||
"suggest_contextLabel": "Dodatkowy kontekst dla AI",
|
||||
"suggest_contextOptional": "(opcjonalny)",
|
||||
"suggest_contextPlaceholder": "np. wieczór imprezowy, skupiam się na nawilżeniu...",
|
||||
"suggest_leavingHomeLabel": "Wychodzę dziś z domu",
|
||||
"suggest_leavingHomeHint": "Wpływa na wybór SPF — zaznaczone: SPF50+, odznaczone: SPF30.",
|
||||
"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_generateBtn": "Generuj propozycję",
|
||||
"suggest_generating": "Generuję…",
|
||||
"suggest_proposalTitle": "Propozycja",
|
||||
"suggest_saveRoutine": "Zapisz rutynę",
|
||||
"suggest_saving": "Zapisuję…",
|
||||
"suggest_regenerate": "Wygeneruj ponownie",
|
||||
"suggest_batchRange": "Zakres dat",
|
||||
"suggest_fromDate": "Od",
|
||||
"suggest_toDate": "Do (max 14 dni)",
|
||||
"suggest_batchContextLabel": "Kontekst / cel wyjazdu",
|
||||
"suggest_batchContextPlaceholder": "np. słoneczna podróż do Włoch, aktywny urlop górski...",
|
||||
"suggest_generatePlan": "Generuj plan",
|
||||
"suggest_generatingPlan": "Generuję plan…",
|
||||
"suggest_planTitle": "Plan ({count} dni)",
|
||||
"suggest_saveAllRoutines": "Zapisz wszystkie rutyny",
|
||||
"suggest_amSteps": "kroków",
|
||||
"suggest_pmSteps": "kroków",
|
||||
"suggest_noAmSteps": "Brak kroków AM.",
|
||||
"suggest_noPmSteps": "Brak kroków PM.",
|
||||
"suggest_errorDefault": "Błąd podczas generowania.",
|
||||
"suggest_errorBatch": "Błąd podczas generowania planu.",
|
||||
"suggest_errorSave": "Błąd podczas zapisywania.",
|
||||
"suggest_amMorning": "AM (rano)",
|
||||
"suggest_pmEvening": "PM (wieczór)",
|
||||
"suggest_title": "Propozycja rutyny AI",
|
||||
"suggest_backToRoutines": "← Rutyny",
|
||||
"suggest_singleTab": "Jedna rutyna",
|
||||
"suggest_batchTab": "Batch / Urlop",
|
||||
"suggest_singleParams": "Parametry",
|
||||
"suggest_date": "Data",
|
||||
"suggest_timeOfDay": "Pora dnia",
|
||||
"suggest_contextLabel": "Dodatkowy kontekst dla AI",
|
||||
"suggest_contextOptional": "(opcjonalny)",
|
||||
"suggest_contextPlaceholder": "np. wieczór imprezowy, skupiam się na nawilżeniu...",
|
||||
"suggest_leavingHomeLabel": "Wychodzę dziś z domu",
|
||||
"suggest_leavingHomeHint": "Wpływa na wybór SPF — zaznaczone: SPF50+, odznaczone: SPF30.",
|
||||
"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_generateBtn": "Generuj propozycję",
|
||||
"suggest_generating": "Generuję…",
|
||||
"suggest_proposalTitle": "Propozycja",
|
||||
"suggest_saveRoutine": "Zapisz rutynę",
|
||||
"suggest_saving": "Zapisuję…",
|
||||
"suggest_regenerate": "Wygeneruj ponownie",
|
||||
"suggest_batchRange": "Zakres dat",
|
||||
"suggest_fromDate": "Od",
|
||||
"suggest_toDate": "Do (max 14 dni)",
|
||||
"suggest_batchContextLabel": "Kontekst / cel wyjazdu",
|
||||
"suggest_batchContextPlaceholder": "np. słoneczna podróż do Włoch, aktywny urlop górski...",
|
||||
"suggest_generatePlan": "Generuj plan",
|
||||
"suggest_generatingPlan": "Generuję plan…",
|
||||
"suggest_planTitle": "Plan ({count} dni)",
|
||||
"suggest_saveAllRoutines": "Zapisz wszystkie rutyny",
|
||||
"suggest_amSteps": "kroków",
|
||||
"suggest_pmSteps": "kroków",
|
||||
"suggest_noAmSteps": "Brak kroków AM.",
|
||||
"suggest_noPmSteps": "Brak kroków PM.",
|
||||
"suggest_errorDefault": "Błąd podczas generowania.",
|
||||
"suggest_errorBatch": "Błąd podczas generowania planu.",
|
||||
"suggest_errorSave": "Błąd podczas zapisywania.",
|
||||
"suggest_amMorning": "AM (rano)",
|
||||
"suggest_pmEvening": "PM (wieczór)",
|
||||
|
||||
"medications_title": "Leki",
|
||||
"medications_count": "{count} wpisów",
|
||||
"medications_addNew": "+ Dodaj lek",
|
||||
"medications_newTitle": "Nowy lek",
|
||||
"medications_kind": "Rodzaj",
|
||||
"medications_productName": "Nazwa produktu *",
|
||||
"medications_productNamePlaceholder": "np. Witamina D3",
|
||||
"medications_activeSubstance": "Substancja czynna",
|
||||
"medications_activeSubstancePlaceholder": "np. cholekalcyferol",
|
||||
"medications_notes": "Notatki",
|
||||
"medications_added": "Lek dodany.",
|
||||
"medications_usages": "{count} użyć",
|
||||
"medications_noMedications": "Brak leków.",
|
||||
"medications_kindPrescription": "Na receptę",
|
||||
"medications_kindOtc": "OTC (bez recepty)",
|
||||
"medications_kindSupplement": "Suplement",
|
||||
"medications_kindHerbal": "Zioła",
|
||||
"medications_kindOther": "Inne",
|
||||
"medications_title": "Leki",
|
||||
"medications_count": "{count} wpisów",
|
||||
"medications_addNew": "+ Dodaj lek",
|
||||
"medications_newTitle": "Nowy lek",
|
||||
"medications_kind": "Rodzaj",
|
||||
"medications_productName": "Nazwa produktu *",
|
||||
"medications_productNamePlaceholder": "np. Witamina D3",
|
||||
"medications_activeSubstance": "Substancja czynna",
|
||||
"medications_activeSubstancePlaceholder": "np. cholekalcyferol",
|
||||
"medications_notes": "Notatki",
|
||||
"medications_added": "Lek dodany.",
|
||||
"medications_usages": "{count} użyć",
|
||||
"medications_noMedications": "Brak leków.",
|
||||
"medications_kindPrescription": "Na receptę",
|
||||
"medications_kindOtc": "OTC (bez recepty)",
|
||||
"medications_kindSupplement": "Suplement",
|
||||
"medications_kindHerbal": "Zioła",
|
||||
"medications_kindOther": "Inne",
|
||||
|
||||
"labResults_title": "Wyniki badań",
|
||||
"labResults_count": "{count} wyników",
|
||||
"labResults_addNew": "+ Dodaj wynik",
|
||||
"labResults_newTitle": "Nowy wynik badania",
|
||||
"labResults_flagFilter": "Flaga:",
|
||||
"labResults_flagAll": "Wszystkie",
|
||||
"labResults_flagNone": "Brak",
|
||||
"labResults_date": "Data *",
|
||||
"labResults_loincCode": "Kod LOINC *",
|
||||
"labResults_testName": "Nazwa badania",
|
||||
"labResults_testNamePlaceholder": "np. Hemoglobina",
|
||||
"labResults_lab": "Laboratorium",
|
||||
"labResults_labPlaceholder": "np. LabCorp",
|
||||
"labResults_value": "Wartość",
|
||||
"labResults_unit": "Jednostka",
|
||||
"labResults_unitPlaceholder": "np. g/dL",
|
||||
"labResults_flag": "Flaga",
|
||||
"labResults_added": "Wynik dodany.",
|
||||
"labResults_colDate": "Data",
|
||||
"labResults_colTest": "Badanie",
|
||||
"labResults_colLoinc": "LOINC",
|
||||
"labResults_colValue": "Wartość",
|
||||
"labResults_colFlag": "Flaga",
|
||||
"labResults_colLab": "Lab",
|
||||
"labResults_noResults": "Nie znaleziono wyników badań.",
|
||||
"labResults_title": "Wyniki badań",
|
||||
"labResults_count": "{count} wyników",
|
||||
"labResults_addNew": "+ Dodaj wynik",
|
||||
"labResults_newTitle": "Nowy wynik badania",
|
||||
"labResults_flagFilter": "Flaga:",
|
||||
"labResults_flagAll": "Wszystkie",
|
||||
"labResults_flagNone": "Brak",
|
||||
"labResults_date": "Data *",
|
||||
"labResults_loincCode": "Kod LOINC *",
|
||||
"labResults_testName": "Nazwa badania",
|
||||
"labResults_testNamePlaceholder": "np. Hemoglobina",
|
||||
"labResults_lab": "Laboratorium",
|
||||
"labResults_labPlaceholder": "np. LabCorp",
|
||||
"labResults_value": "Wartość",
|
||||
"labResults_unit": "Jednostka",
|
||||
"labResults_unitPlaceholder": "np. g/dL",
|
||||
"labResults_flag": "Flaga",
|
||||
"labResults_added": "Wynik dodany.",
|
||||
"labResults_colDate": "Data",
|
||||
"labResults_colTest": "Badanie",
|
||||
"labResults_colLoinc": "LOINC",
|
||||
"labResults_colValue": "Wartość",
|
||||
"labResults_colFlag": "Flaga",
|
||||
"labResults_colLab": "Lab",
|
||||
"labResults_noResults": "Nie znaleziono wyników badań.",
|
||||
|
||||
"skin_title": "Stan skóry",
|
||||
"skin_count": "{count} wpisów",
|
||||
"skin_addNew": "+ Dodaj wpis",
|
||||
"skin_aiAnalysisTitle": "Analiza AI ze zdjęć",
|
||||
"skin_aiUploadText": "Prześlij 1–3 zdjęcia skóry. AI wypełni pola formularza poniżej.",
|
||||
"skin_analyzePhotos": "Analizuj zdjęcia",
|
||||
"skin_analyzing": "Analizuję…",
|
||||
"skin_newSnapshotTitle": "Nowy wpis",
|
||||
"skin_date": "Data *",
|
||||
"skin_overallState": "Ogólny stan",
|
||||
"skin_texture": "Tekstura",
|
||||
"skin_skinType": "Typ skóry",
|
||||
"skin_barrierState": "Stan bariery",
|
||||
"skin_hydration": "Nawilżenie (1–5)",
|
||||
"skin_sensitivity": "Wrażliwość (1–5)",
|
||||
"skin_sebumTzone": "Sebum T-zone (1–5)",
|
||||
"skin_sebumCheeks": "Sebum policzki (1–5)",
|
||||
"skin_activeConcerns": "Aktywne problemy (przecinek)",
|
||||
"skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie",
|
||||
"skin_priorities": "Priorytety (przecinek)",
|
||||
"skin_prioritiesPlaceholder": "wzmocnić barierę, redukować zaczerwienienie",
|
||||
"skin_prioritiesLabel": "Priorytety",
|
||||
"skin_notes": "Notatki",
|
||||
"skin_addSnapshot": "Dodaj wpis",
|
||||
"skin_snapshotAdded": "Wpis dodany.",
|
||||
"skin_snapshotUpdated": "Wpis zaktualizowany.",
|
||||
"skin_snapshotDeleted": "Wpis usunięty.",
|
||||
"skin_noSnapshots": "Brak wpisów o stanie skóry.",
|
||||
"skin_hydrationLabel": "Nawilżenie",
|
||||
"skin_sensitivityLabel": "Wrażliwość",
|
||||
"skin_barrierLabel": "Bariera",
|
||||
"skin_stateExcellent": "doskonały",
|
||||
"skin_stateGood": "dobry",
|
||||
"skin_stateFair": "przeciętny",
|
||||
"skin_statePoor": "zły",
|
||||
"skin_textureSmooth": "gładka",
|
||||
"skin_textureRough": "szorstka",
|
||||
"skin_textureFlaky": "łuszcząca się",
|
||||
"skin_textureBumpy": "nierówna",
|
||||
"skin_barrierIntact": "nienaruszona",
|
||||
"skin_barrierMildly": "lekko naruszona",
|
||||
"skin_barrierCompromised": "naruszona",
|
||||
"skin_typeDry": "sucha",
|
||||
"skin_typeOily": "tłusta",
|
||||
"skin_typeCombination": "mieszana",
|
||||
"skin_typeSensitive": "wrażliwa",
|
||||
"skin_typeNormal": "normalna",
|
||||
"skin_typeAcneProne": "trądzikowa",
|
||||
"skin_title": "Stan skóry",
|
||||
"skin_count": "{count} wpisów",
|
||||
"skin_addNew": "+ Dodaj wpis",
|
||||
"skin_aiAnalysisTitle": "Analiza AI ze zdjęć",
|
||||
"skin_aiUploadText": "Prześlij 1–3 zdjęcia skóry. AI wypełni pola formularza poniżej.",
|
||||
"skin_analyzePhotos": "Analizuj zdjęcia",
|
||||
"skin_analyzing": "Analizuję…",
|
||||
"skin_newSnapshotTitle": "Nowy wpis",
|
||||
"skin_date": "Data *",
|
||||
"skin_overallState": "Ogólny stan",
|
||||
"skin_texture": "Tekstura",
|
||||
"skin_skinType": "Typ skóry",
|
||||
"skin_barrierState": "Stan bariery",
|
||||
"skin_hydration": "Nawilżenie (1–5)",
|
||||
"skin_sensitivity": "Wrażliwość (1–5)",
|
||||
"skin_sebumTzone": "Sebum T-zone (1–5)",
|
||||
"skin_sebumCheeks": "Sebum policzki (1–5)",
|
||||
"skin_activeConcerns": "Aktywne problemy (przecinek)",
|
||||
"skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie",
|
||||
"skin_priorities": "Priorytety (przecinek)",
|
||||
"skin_prioritiesPlaceholder": "wzmocnić barierę, redukować zaczerwienienie",
|
||||
"skin_prioritiesLabel": "Priorytety",
|
||||
"skin_notes": "Notatki",
|
||||
"skin_addSnapshot": "Dodaj wpis",
|
||||
"skin_snapshotAdded": "Wpis dodany.",
|
||||
"skin_snapshotUpdated": "Wpis zaktualizowany.",
|
||||
"skin_snapshotDeleted": "Wpis usunięty.",
|
||||
"skin_noSnapshots": "Brak wpisów o stanie skóry.",
|
||||
"skin_hydrationLabel": "Nawilżenie",
|
||||
"skin_sensitivityLabel": "Wrażliwość",
|
||||
"skin_barrierLabel": "Bariera",
|
||||
"skin_stateExcellent": "doskonały",
|
||||
"skin_stateGood": "dobry",
|
||||
"skin_stateFair": "przeciętny",
|
||||
"skin_statePoor": "zły",
|
||||
"skin_textureSmooth": "gładka",
|
||||
"skin_textureRough": "szorstka",
|
||||
"skin_textureFlaky": "łuszcząca się",
|
||||
"skin_textureBumpy": "nierówna",
|
||||
"skin_barrierIntact": "nienaruszona",
|
||||
"skin_barrierMildly": "lekko naruszona",
|
||||
"skin_barrierCompromised": "naruszona",
|
||||
"skin_typeDry": "sucha",
|
||||
"skin_typeOily": "tłusta",
|
||||
"skin_typeCombination": "mieszana",
|
||||
"skin_typeSensitive": "wrażliwa",
|
||||
"skin_typeNormal": "normalna",
|
||||
"skin_typeAcneProne": "trądzikowa",
|
||||
|
||||
"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_pasteText": "Wklej tutaj opis produktu, składniki INCI...",
|
||||
"productForm_parseWithAI": "Uzupełnij pola (AI)",
|
||||
"productForm_parsing": "Przetwarzam…",
|
||||
"productForm_basicInfo": "Informacje podstawowe",
|
||||
"productForm_name": "Nazwa *",
|
||||
"productForm_namePlaceholder": "np. Hydro Boost Water Gel",
|
||||
"productForm_brand": "Marka *",
|
||||
"productForm_brandPlaceholder": "np. Neutrogena",
|
||||
"productForm_lineName": "Linia / seria",
|
||||
"productForm_lineNamePlaceholder": "np. Hydro Boost",
|
||||
"productForm_url": "URL",
|
||||
"productForm_sku": "SKU",
|
||||
"productForm_skuPlaceholder": "np. NTR-HB-50",
|
||||
"productForm_barcode": "Kod kreskowy / EAN",
|
||||
"productForm_barcodePlaceholder": "np. 3614273258975",
|
||||
"productForm_classification": "Klasyfikacja",
|
||||
"productForm_category": "Kategoria *",
|
||||
"productForm_selectCategory": "Wybierz kategorię",
|
||||
"productForm_time": "Pora *",
|
||||
"productForm_timeOptions": "AM / PM / Oba",
|
||||
"productForm_timeBoth": "Oba",
|
||||
"productForm_leaveOn": "Leave-on *",
|
||||
"productForm_leaveOnYes": "Tak (leave-on)",
|
||||
"productForm_leaveOnNo": "Nie (rinse-off)",
|
||||
"productForm_texture": "Tekstura",
|
||||
"productForm_selectTexture": "Wybierz teksturę",
|
||||
"productForm_absorptionSpeed": "Szybkość wchłaniania",
|
||||
"productForm_selectSpeed": "Wybierz szybkość",
|
||||
"productForm_skinProfile": "Profil skóry",
|
||||
"productForm_recommendedFor": "Polecane dla typów skóry",
|
||||
"productForm_targetConcerns": "Problemy docelowe",
|
||||
"productForm_contraindications": "Przeciwwskazania (jedno na linię)",
|
||||
"productForm_contraindicationsPlaceholder": "np. aktywna rosacea",
|
||||
"productForm_ingredients": "Składniki",
|
||||
"productForm_inciList": "Lista INCI (jeden składnik na linię)",
|
||||
"productForm_activeIngredients": "Składniki aktywne",
|
||||
"productForm_addActive": "+ Dodaj aktywny",
|
||||
"productForm_noActives": "Brak składników aktywnych.",
|
||||
"productForm_activeName": "Nazwa",
|
||||
"productForm_activePercent": "%",
|
||||
"productForm_activeStrength": "Siła",
|
||||
"productForm_activeIrritation": "Podrażnienie",
|
||||
"productForm_activeFunctions": "Funkcje",
|
||||
"productForm_effectProfile": "Profil działania (0–5)",
|
||||
"productForm_interactions": "Interakcje",
|
||||
"productForm_synergizesWith": "Synergizuje z (jedno na linię)",
|
||||
"productForm_incompatibleWith": "Niekompatybilny z",
|
||||
"productForm_addIncompatibility": "+ Dodaj niekompatybilność",
|
||||
"productForm_noIncompatibilities": "Brak niekompatybilności.",
|
||||
"productForm_incompTarget": "Składnik docelowy",
|
||||
"productForm_incompScope": "Zakres",
|
||||
"productForm_incompReason": "Powód (opcjonalny)",
|
||||
"productForm_incompReasonPlaceholder": "np. zmniejsza skuteczność",
|
||||
"productForm_incompScopeSelect": "Wybierz…",
|
||||
"productForm_contextRules": "Reguły kontekstu",
|
||||
"productForm_ctxAfterShaving": "Bezpieczny po goleniu",
|
||||
"productForm_ctxAfterAcids": "Bezpieczny po kwasach",
|
||||
"productForm_ctxAfterRetinoids": "Bezpieczny po retinoidach",
|
||||
"productForm_ctxCompromisedBarrier": "Bezpieczny przy naruszonej barierze",
|
||||
"productForm_ctxLowUvOnly": "Tylko przy niskim UV (wieczór/zakrycie)",
|
||||
"productForm_productDetails": "Szczegóły produktu",
|
||||
"productForm_priceTier": "Przedział cenowy",
|
||||
"productForm_selectTier": "Wybierz przedział",
|
||||
"productForm_sizeMl": "Rozmiar (ml)",
|
||||
"productForm_fullWeightG": "Waga pełna (g)",
|
||||
"productForm_emptyWeightG": "Waga pustego (g)",
|
||||
"productForm_paoMonths": "PAO (miesiące)",
|
||||
"productForm_phMin": "pH min",
|
||||
"productForm_phMax": "pH max",
|
||||
"productForm_usageNotes": "Notatki o stosowaniu",
|
||||
"productForm_usageNotesPlaceholder": "np. Nakładaj na wilgotną skórę, unikaj okolic oczu",
|
||||
"productForm_safetyFlags": "Flagi bezpieczeństwa",
|
||||
"productForm_fragranceFree": "Bez zapachów",
|
||||
"productForm_essentialOilsFree": "Bez olejków eterycznych",
|
||||
"productForm_alcoholDenatFree": "Bez alkoholu denat.",
|
||||
"productForm_pregnancySafe": "Bezpieczny w ciąży",
|
||||
"productForm_usageConstraints": "Ograniczenia stosowania",
|
||||
"productForm_minIntervalHours": "Min. przerwa (godziny)",
|
||||
"productForm_maxFrequencyPerWeek": "Max użyć na tydzień",
|
||||
"productForm_isMedication": "To lek",
|
||||
"productForm_isTool": "To narzędzie (np. dermaroller)",
|
||||
"productForm_needleLengthMm": "Długość igły (mm, tylko narzędzia)",
|
||||
"productForm_personalNotes": "Notatki osobiste",
|
||||
"productForm_repurchaseIntent": "Zamiar ponownego zakupu",
|
||||
"productForm_toleranceNotes": "Notatki o tolerancji",
|
||||
"productForm_toleranceNotesPlaceholder": "np. Lekkie pieczenie, ustępuje po 2 tygodniach",
|
||||
"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_pasteText": "Wklej tutaj opis produktu, składniki INCI...",
|
||||
"productForm_parseWithAI": "Uzupełnij pola (AI)",
|
||||
"productForm_parsing": "Przetwarzam…",
|
||||
"productForm_basicInfo": "Informacje podstawowe",
|
||||
"productForm_name": "Nazwa *",
|
||||
"productForm_namePlaceholder": "np. Hydro Boost Water Gel",
|
||||
"productForm_brand": "Marka *",
|
||||
"productForm_brandPlaceholder": "np. Neutrogena",
|
||||
"productForm_lineName": "Linia / seria",
|
||||
"productForm_lineNamePlaceholder": "np. Hydro Boost",
|
||||
"productForm_url": "URL",
|
||||
"productForm_sku": "SKU",
|
||||
"productForm_skuPlaceholder": "np. NTR-HB-50",
|
||||
"productForm_barcode": "Kod kreskowy / EAN",
|
||||
"productForm_barcodePlaceholder": "np. 3614273258975",
|
||||
"productForm_classification": "Klasyfikacja",
|
||||
"productForm_category": "Kategoria *",
|
||||
"productForm_selectCategory": "Wybierz kategorię",
|
||||
"productForm_time": "Pora *",
|
||||
"productForm_timeOptions": "AM / PM / Oba",
|
||||
"productForm_timeBoth": "Oba",
|
||||
"productForm_leaveOn": "Leave-on *",
|
||||
"productForm_leaveOnYes": "Tak (leave-on)",
|
||||
"productForm_leaveOnNo": "Nie (rinse-off)",
|
||||
"productForm_texture": "Tekstura",
|
||||
"productForm_selectTexture": "Wybierz teksturę",
|
||||
"productForm_absorptionSpeed": "Szybkość wchłaniania",
|
||||
"productForm_selectSpeed": "Wybierz szybkość",
|
||||
"productForm_skinProfile": "Profil skóry",
|
||||
"productForm_recommendedFor": "Polecane dla typów skóry",
|
||||
"productForm_targetConcerns": "Problemy docelowe",
|
||||
"productForm_contraindications": "Przeciwwskazania (jedno na linię)",
|
||||
"productForm_contraindicationsPlaceholder": "np. aktywna rosacea",
|
||||
"productForm_ingredients": "Składniki",
|
||||
"productForm_inciList": "Lista INCI (jeden składnik na linię)",
|
||||
"productForm_activeIngredients": "Składniki aktywne",
|
||||
"productForm_addActive": "+ Dodaj aktywny",
|
||||
"productForm_noActives": "Brak składników aktywnych.",
|
||||
"productForm_activeName": "Nazwa",
|
||||
"productForm_activePercent": "%",
|
||||
"productForm_activeStrength": "Siła",
|
||||
"productForm_activeIrritation": "Podrażnienie",
|
||||
"productForm_activeFunctions": "Funkcje",
|
||||
"productForm_effectProfile": "Profil działania (0–5)",
|
||||
"productForm_interactions": "Interakcje",
|
||||
"productForm_synergizesWith": "Synergizuje z (jedno na linię)",
|
||||
"productForm_incompatibleWith": "Niekompatybilny z",
|
||||
"productForm_addIncompatibility": "+ Dodaj niekompatybilność",
|
||||
"productForm_noIncompatibilities": "Brak niekompatybilności.",
|
||||
"productForm_incompTarget": "Składnik docelowy",
|
||||
"productForm_incompScope": "Zakres",
|
||||
"productForm_incompReason": "Powód (opcjonalny)",
|
||||
"productForm_incompReasonPlaceholder": "np. zmniejsza skuteczność",
|
||||
"productForm_incompScopeSelect": "Wybierz…",
|
||||
"productForm_contextRules": "Reguły kontekstu",
|
||||
"productForm_ctxAfterShaving": "Bezpieczny po goleniu",
|
||||
"productForm_ctxAfterAcids": "Bezpieczny po kwasach",
|
||||
"productForm_ctxAfterRetinoids": "Bezpieczny po retinoidach",
|
||||
"productForm_ctxCompromisedBarrier": "Bezpieczny przy naruszonej barierze",
|
||||
"productForm_ctxLowUvOnly": "Tylko przy niskim UV (wieczór/zakrycie)",
|
||||
"productForm_productDetails": "Szczegóły produktu",
|
||||
"productForm_priceTier": "Przedział cenowy",
|
||||
"productForm_selectTier": "Wybierz przedział",
|
||||
"productForm_sizeMl": "Rozmiar (ml)",
|
||||
"productForm_fullWeightG": "Waga pełna (g)",
|
||||
"productForm_emptyWeightG": "Waga pustego (g)",
|
||||
"productForm_paoMonths": "PAO (miesiące)",
|
||||
"productForm_phMin": "pH min",
|
||||
"productForm_phMax": "pH max",
|
||||
"productForm_usageNotes": "Notatki o stosowaniu",
|
||||
"productForm_usageNotesPlaceholder": "np. Nakładaj na wilgotną skórę, unikaj okolic oczu",
|
||||
"productForm_safetyFlags": "Flagi bezpieczeństwa",
|
||||
"productForm_fragranceFree": "Bez zapachów",
|
||||
"productForm_essentialOilsFree": "Bez olejków eterycznych",
|
||||
"productForm_alcoholDenatFree": "Bez alkoholu denat.",
|
||||
"productForm_pregnancySafe": "Bezpieczny w ciąży",
|
||||
"productForm_usageConstraints": "Ograniczenia stosowania",
|
||||
"productForm_minIntervalHours": "Min. przerwa (godziny)",
|
||||
"productForm_maxFrequencyPerWeek": "Max użyć na tydzień",
|
||||
"productForm_isMedication": "To lek",
|
||||
"productForm_isTool": "To narzędzie (np. dermaroller)",
|
||||
"productForm_needleLengthMm": "Długość igły (mm, tylko narzędzia)",
|
||||
"productForm_personalNotes": "Notatki osobiste",
|
||||
"productForm_repurchaseIntent": "Zamiar ponownego zakupu",
|
||||
"productForm_toleranceNotes": "Notatki o tolerancji",
|
||||
"productForm_toleranceNotesPlaceholder": "np. Lekkie pieczenie, ustępuje po 2 tygodniach",
|
||||
|
||||
"productForm_categoryCleanser": "Żel/pianka do mycia",
|
||||
"productForm_categoryToner": "Tonik",
|
||||
"productForm_categoryEssence": "Esencja",
|
||||
"productForm_categorySerum": "Serum",
|
||||
"productForm_categoryMoisturizer": "Krem",
|
||||
"productForm_categorySpf": "SPF",
|
||||
"productForm_categoryMask": "Maska",
|
||||
"productForm_categoryExfoliant": "Peeling",
|
||||
"productForm_categoryHairTreatment": "Pielęgnacja włosów",
|
||||
"productForm_categoryTool": "Narzędzie",
|
||||
"productForm_categorySpotTreatment": "Punkt leczenia",
|
||||
"productForm_categoryOil": "Olejek",
|
||||
"productForm_categoryCleanser": "Żel/pianka do mycia",
|
||||
"productForm_categoryToner": "Tonik",
|
||||
"productForm_categoryEssence": "Esencja",
|
||||
"productForm_categorySerum": "Serum",
|
||||
"productForm_categoryMoisturizer": "Krem",
|
||||
"productForm_categorySpf": "SPF",
|
||||
"productForm_categoryMask": "Maska",
|
||||
"productForm_categoryExfoliant": "Peeling",
|
||||
"productForm_categoryHairTreatment": "Pielęgnacja włosów",
|
||||
"productForm_categoryTool": "Narzędzie",
|
||||
"productForm_categorySpotTreatment": "Punkt leczenia",
|
||||
"productForm_categoryOil": "Olejek",
|
||||
|
||||
"productForm_textureWatery": "Wodnista",
|
||||
"productForm_textureGel": "Żel",
|
||||
"productForm_textureEmulsion": "Emulsja",
|
||||
"productForm_textureCream": "Krem",
|
||||
"productForm_textureOil": "Olejek",
|
||||
"productForm_textureBalm": "Balsam",
|
||||
"productForm_textureFoam": "Pianka",
|
||||
"productForm_textureFluid": "Fluid",
|
||||
"productForm_textureWatery": "Wodnista",
|
||||
"productForm_textureGel": "Żel",
|
||||
"productForm_textureEmulsion": "Emulsja",
|
||||
"productForm_textureCream": "Krem",
|
||||
"productForm_textureOil": "Olejek",
|
||||
"productForm_textureBalm": "Balsam",
|
||||
"productForm_textureFoam": "Pianka",
|
||||
"productForm_textureFluid": "Fluid",
|
||||
|
||||
"productForm_absorptionVeryFast": "Bardzo szybkie",
|
||||
"productForm_absorptionFast": "Szybkie",
|
||||
"productForm_absorptionModerate": "Umiarkowane",
|
||||
"productForm_absorptionSlow": "Wolne",
|
||||
"productForm_absorptionVerySlow": "Bardzo wolne",
|
||||
"productForm_absorptionVeryFast": "Bardzo szybkie",
|
||||
"productForm_absorptionFast": "Szybkie",
|
||||
"productForm_absorptionModerate": "Umiarkowane",
|
||||
"productForm_absorptionSlow": "Wolne",
|
||||
"productForm_absorptionVerySlow": "Bardzo wolne",
|
||||
|
||||
"productForm_priceBudget": "Budżetowy",
|
||||
"productForm_priceMid": "Średni",
|
||||
"productForm_pricePremium": "Premium",
|
||||
"productForm_priceLuxury": "Luksusowy",
|
||||
"productForm_priceBudget": "Budżetowy",
|
||||
"productForm_priceMid": "Średni",
|
||||
"productForm_pricePremium": "Premium",
|
||||
"productForm_priceLuxury": "Luksusowy",
|
||||
|
||||
"productForm_skinTypeDry": "sucha",
|
||||
"productForm_skinTypeOily": "tłusta",
|
||||
"productForm_skinTypeCombination": "mieszana",
|
||||
"productForm_skinTypeSensitive": "wrażliwa",
|
||||
"productForm_skinTypeNormal": "normalna",
|
||||
"productForm_skinTypeAcneProne": "trądzikowa",
|
||||
"productForm_skinTypeDry": "sucha",
|
||||
"productForm_skinTypeOily": "tłusta",
|
||||
"productForm_skinTypeCombination": "mieszana",
|
||||
"productForm_skinTypeSensitive": "wrażliwa",
|
||||
"productForm_skinTypeNormal": "normalna",
|
||||
"productForm_skinTypeAcneProne": "trądzikowa",
|
||||
|
||||
"productForm_concernAcne": "trądzik",
|
||||
"productForm_concernRosacea": "rosacea",
|
||||
"productForm_concernHyperpigmentation": "przebarwienia",
|
||||
"productForm_concernAging": "starzenie",
|
||||
"productForm_concernDehydration": "odwodnienie",
|
||||
"productForm_concernRedness": "zaczerwienienie",
|
||||
"productForm_concernDamagedBarrier": "naruszona bariera",
|
||||
"productForm_concernPoreVisibility": "widoczność porów",
|
||||
"productForm_concernUnevenTexture": "nierówna tekstura",
|
||||
"productForm_concernHairGrowth": "wzrost włosów",
|
||||
"productForm_concernSebumExcess": "nadmiar sebum",
|
||||
"productForm_concernAcne": "trądzik",
|
||||
"productForm_concernRosacea": "rosacea",
|
||||
"productForm_concernHyperpigmentation": "przebarwienia",
|
||||
"productForm_concernAging": "starzenie",
|
||||
"productForm_concernDehydration": "odwodnienie",
|
||||
"productForm_concernRedness": "zaczerwienienie",
|
||||
"productForm_concernDamagedBarrier": "naruszona bariera",
|
||||
"productForm_concernPoreVisibility": "widoczność porów",
|
||||
"productForm_concernUnevenTexture": "nierówna tekstura",
|
||||
"productForm_concernHairGrowth": "wzrost włosów",
|
||||
"productForm_concernSebumExcess": "nadmiar sebum",
|
||||
|
||||
"productForm_fnHumectant": "humektant",
|
||||
"productForm_fnEmollient": "emolient",
|
||||
"productForm_fnOcclusive": "okluzja",
|
||||
"productForm_fnExfoliantAha": "peeling AHA",
|
||||
"productForm_fnExfoliantBha": "peeling BHA",
|
||||
"productForm_fnExfoliantPha": "peeling PHA",
|
||||
"productForm_fnRetinoid": "retinoid",
|
||||
"productForm_fnAntioxidant": "antyoksydant",
|
||||
"productForm_fnSoothing": "łagodzący",
|
||||
"productForm_fnBarrierSupport": "wsparcie bariery",
|
||||
"productForm_fnBrightening": "rozjaśniający",
|
||||
"productForm_fnAntiAcne": "przeciwtrądzikowy",
|
||||
"productForm_fnCeramide": "ceramid",
|
||||
"productForm_fnNiacinamide": "niacynamid",
|
||||
"productForm_fnSunscreen": "filtr UV",
|
||||
"productForm_fnPeptide": "peptyd",
|
||||
"productForm_fnHairGrowth": "stymulator wzrostu włosów",
|
||||
"productForm_fnPrebiotic": "prebiotyk",
|
||||
"productForm_fnVitaminC": "witamina C",
|
||||
"productForm_fnAntiAging": "przeciwstarzeniowy",
|
||||
"productForm_fnHumectant": "humektant",
|
||||
"productForm_fnEmollient": "emolient",
|
||||
"productForm_fnOcclusive": "okluzja",
|
||||
"productForm_fnExfoliantAha": "peeling AHA",
|
||||
"productForm_fnExfoliantBha": "peeling BHA",
|
||||
"productForm_fnExfoliantPha": "peeling PHA",
|
||||
"productForm_fnRetinoid": "retinoid",
|
||||
"productForm_fnAntioxidant": "antyoksydant",
|
||||
"productForm_fnSoothing": "łagodzący",
|
||||
"productForm_fnBarrierSupport": "wsparcie bariery",
|
||||
"productForm_fnBrightening": "rozjaśniający",
|
||||
"productForm_fnAntiAcne": "przeciwtrądzikowy",
|
||||
"productForm_fnCeramide": "ceramid",
|
||||
"productForm_fnNiacinamide": "niacynamid",
|
||||
"productForm_fnSunscreen": "filtr UV",
|
||||
"productForm_fnPeptide": "peptyd",
|
||||
"productForm_fnHairGrowth": "stymulator wzrostu włosów",
|
||||
"productForm_fnPrebiotic": "prebiotyk",
|
||||
"productForm_fnVitaminC": "witamina C",
|
||||
"productForm_fnAntiAging": "przeciwstarzeniowy",
|
||||
|
||||
"productForm_scopeSameStep": "ten sam krok",
|
||||
"productForm_scopeSameDay": "ten sam dzień",
|
||||
"productForm_scopeSamePeriod": "ten sam okres",
|
||||
"productForm_scopeSameStep": "ten sam krok",
|
||||
"productForm_scopeSameDay": "ten sam dzień",
|
||||
"productForm_scopeSamePeriod": "ten sam okres",
|
||||
|
||||
"productForm_strengthLow": "1 Niskie",
|
||||
"productForm_strengthMedium": "2 Średnie",
|
||||
"productForm_strengthHigh": "3 Wysokie",
|
||||
"productForm_strengthLow": "1 Niskie",
|
||||
"productForm_strengthMedium": "2 Średnie",
|
||||
"productForm_strengthHigh": "3 Wysokie",
|
||||
|
||||
"productForm_effectHydrationImmediate": "Nawilżenie (natychmiastowe)",
|
||||
"productForm_effectHydrationLongTerm": "Nawilżenie (długoterminowe)",
|
||||
"productForm_effectBarrierRepair": "Naprawa bariery",
|
||||
"productForm_effectSoothing": "Łagodzenie",
|
||||
"productForm_effectExfoliation": "Złuszczanie",
|
||||
"productForm_effectRetinoid": "Aktywność retinoidu",
|
||||
"productForm_effectIrritation": "Ryzyko podrażnienia",
|
||||
"productForm_effectComedogenic": "Ryzyko komedogenności",
|
||||
"productForm_effectBarrierDisruption": "Ryzyko naruszenia bariery",
|
||||
"productForm_effectDryness": "Ryzyko przesuszenia",
|
||||
"productForm_effectBrightening": "Rozjaśnienie",
|
||||
"productForm_effectAntiAcne": "Działanie przeciwtrądzikowe",
|
||||
"productForm_effectAntiAging": "Działanie przeciwstarzeniowe",
|
||||
"productForm_effectHydrationImmediate": "Nawilżenie (natychmiastowe)",
|
||||
"productForm_effectHydrationLongTerm": "Nawilżenie (długoterminowe)",
|
||||
"productForm_effectBarrierRepair": "Naprawa bariery",
|
||||
"productForm_effectSoothing": "Łagodzenie",
|
||||
"productForm_effectExfoliation": "Złuszczanie",
|
||||
"productForm_effectRetinoid": "Aktywność retinoidu",
|
||||
"productForm_effectIrritation": "Ryzyko podrażnienia",
|
||||
"productForm_effectComedogenic": "Ryzyko komedogenności",
|
||||
"productForm_effectBarrierDisruption": "Ryzyko naruszenia bariery",
|
||||
"productForm_effectDryness": "Ryzyko przesuszenia",
|
||||
"productForm_effectBrightening": "Rozjaśnienie",
|
||||
"productForm_effectAntiAcne": "Działanie przeciwtrądzikowe",
|
||||
"productForm_effectAntiAging": "Działanie przeciwstarzeniowe",
|
||||
|
||||
"lang_pl": "PL",
|
||||
"lang_en": "EN"
|
||||
"lang_pl": "PL",
|
||||
"lang_en": "EN"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"$schema": "https://inlang.com/schema/project-settings",
|
||||
"baseLocale": "pl",
|
||||
"locales": ["pl", "en"],
|
||||
"modules": [
|
||||
"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"
|
||||
],
|
||||
"plugin.inlang.messageFormat": {
|
||||
"pathPattern": "./messages/{locale}.json"
|
||||
}
|
||||
"$schema": "https://inlang.com/schema/project-settings",
|
||||
"baseLocale": "pl",
|
||||
"locales": ["pl", "en"],
|
||||
"modules": [
|
||||
"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"
|
||||
],
|
||||
"plugin.inlang.messageFormat": {
|
||||
"pathPattern": "./messages/{locale}.json"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,85 +5,85 @@
|
|||
/* ── CSS variable definitions (light / dark) ─────────────────────────────── */
|
||||
|
||||
:root {
|
||||
--background: hsl(0 0% 100%);
|
||||
--foreground: hsl(240 10% 3.9%);
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(240 10% 3.9%);
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(240 10% 3.9%);
|
||||
--primary: hsl(240 5.9% 10%);
|
||||
--primary-foreground: hsl(0 0% 98%);
|
||||
--secondary: hsl(240 4.8% 95.9%);
|
||||
--secondary-foreground: hsl(240 5.9% 10%);
|
||||
--muted: hsl(240 4.8% 95.9%);
|
||||
--muted-foreground: hsl(240 3.8% 46.1%);
|
||||
--accent: hsl(240 4.8% 95.9%);
|
||||
--accent-foreground: hsl(240 5.9% 10%);
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 5.9% 90%);
|
||||
--input: hsl(240 5.9% 90%);
|
||||
--ring: hsl(240 5.9% 10%);
|
||||
--radius: 0.5rem;
|
||||
--background: hsl(0 0% 100%);
|
||||
--foreground: hsl(240 10% 3.9%);
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(240 10% 3.9%);
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(240 10% 3.9%);
|
||||
--primary: hsl(240 5.9% 10%);
|
||||
--primary-foreground: hsl(0 0% 98%);
|
||||
--secondary: hsl(240 4.8% 95.9%);
|
||||
--secondary-foreground: hsl(240 5.9% 10%);
|
||||
--muted: hsl(240 4.8% 95.9%);
|
||||
--muted-foreground: hsl(240 3.8% 46.1%);
|
||||
--accent: hsl(240 4.8% 95.9%);
|
||||
--accent-foreground: hsl(240 5.9% 10%);
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 5.9% 90%);
|
||||
--input: hsl(240 5.9% 90%);
|
||||
--ring: hsl(240 5.9% 10%);
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: hsl(240 10% 3.9%);
|
||||
--foreground: hsl(0 0% 98%);
|
||||
--card: hsl(240 10% 3.9%);
|
||||
--card-foreground: hsl(0 0% 98%);
|
||||
--popover: hsl(240 10% 3.9%);
|
||||
--popover-foreground: hsl(0 0% 98%);
|
||||
--primary: hsl(0 0% 98%);
|
||||
--primary-foreground: hsl(240 5.9% 10%);
|
||||
--secondary: hsl(240 3.7% 15.9%);
|
||||
--secondary-foreground: hsl(0 0% 98%);
|
||||
--muted: hsl(240 3.7% 15.9%);
|
||||
--muted-foreground: hsl(240 5% 64.9%);
|
||||
--accent: hsl(240 3.7% 15.9%);
|
||||
--accent-foreground: hsl(0 0% 98%);
|
||||
--destructive: hsl(0 62.8% 30.6%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 3.7% 15.9%);
|
||||
--input: hsl(240 3.7% 15.9%);
|
||||
--ring: hsl(240 4.9% 83.9%);
|
||||
--background: hsl(240 10% 3.9%);
|
||||
--foreground: hsl(0 0% 98%);
|
||||
--card: hsl(240 10% 3.9%);
|
||||
--card-foreground: hsl(0 0% 98%);
|
||||
--popover: hsl(240 10% 3.9%);
|
||||
--popover-foreground: hsl(0 0% 98%);
|
||||
--primary: hsl(0 0% 98%);
|
||||
--primary-foreground: hsl(240 5.9% 10%);
|
||||
--secondary: hsl(240 3.7% 15.9%);
|
||||
--secondary-foreground: hsl(0 0% 98%);
|
||||
--muted: hsl(240 3.7% 15.9%);
|
||||
--muted-foreground: hsl(240 5% 64.9%);
|
||||
--accent: hsl(240 3.7% 15.9%);
|
||||
--accent-foreground: hsl(0 0% 98%);
|
||||
--destructive: hsl(0 62.8% 30.6%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 3.7% 15.9%);
|
||||
--input: hsl(240 3.7% 15.9%);
|
||||
--ring: hsl(240 4.9% 83.9%);
|
||||
}
|
||||
|
||||
/* ── Map CSS vars → Tailwind v4 design tokens ────────────────────────────── */
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
/* ── Base resets ─────────────────────────────────────────────────────────── */
|
||||
|
||||
* {
|
||||
border-color: var(--border);
|
||||
border-color: var(--border);
|
||||
}
|
||||
body {
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
|
|
|||
14
frontend/src/app.d.ts
vendored
14
frontend/src/app.d.ts
vendored
|
|
@ -1,13 +1,13 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { paraglideMiddleware } from '$lib/paraglide/server.js';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import { paraglideMiddleware } from "$lib/paraglide/server.js";
|
||||
import type { Handle } from "@sveltejs/kit";
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
return paraglideMiddleware(event.request, () => resolve(event));
|
||||
return paraglideMiddleware(event.request, () => resolve(event));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,280 +1,349 @@
|
|||
import { browser } from '$app/environment';
|
||||
import { PUBLIC_API_BASE } from '$env/static/public';
|
||||
import { browser } from "$app/environment";
|
||||
import { PUBLIC_API_BASE } from "$env/static/public";
|
||||
import type {
|
||||
ActiveIngredient,
|
||||
BatchSuggestion,
|
||||
GroomingSchedule,
|
||||
LabResult,
|
||||
MedicationEntry,
|
||||
MedicationUsage,
|
||||
PartOfDay,
|
||||
Product,
|
||||
ProductContext,
|
||||
ProductEffectProfile,
|
||||
ProductInteraction,
|
||||
ProductInventory,
|
||||
Routine,
|
||||
RoutineSuggestion,
|
||||
RoutineStep,
|
||||
SkinConditionSnapshot
|
||||
} from './types';
|
||||
ActiveIngredient,
|
||||
BatchSuggestion,
|
||||
GroomingSchedule,
|
||||
LabResult,
|
||||
MedicationEntry,
|
||||
MedicationUsage,
|
||||
PartOfDay,
|
||||
Product,
|
||||
ProductContext,
|
||||
ProductEffectProfile,
|
||||
ProductInteraction,
|
||||
ProductInventory,
|
||||
Routine,
|
||||
RoutineSuggestion,
|
||||
RoutineStep,
|
||||
SkinConditionSnapshot,
|
||||
} from "./types";
|
||||
|
||||
// ─── Core fetch helpers ──────────────────────────────────────────────────────
|
||||
|
||||
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
// Server-side uses PUBLIC_API_BASE (e.g. http://localhost:8000).
|
||||
// Browser-side uses /api so nginx proxies the request on the correct host.
|
||||
const base = browser ? '/api' : PUBLIC_API_BASE;
|
||||
const url = `${base}${path}`;
|
||||
const res = await fetch(url, {
|
||||
headers: { 'Content-Type': 'application/json', ...init.headers },
|
||||
...init
|
||||
});
|
||||
if (!res.ok) {
|
||||
const detail = await res.json().catch(() => ({ detail: res.statusText }));
|
||||
throw new Error(detail?.detail ?? res.statusText);
|
||||
}
|
||||
if (res.status === 204) return undefined as T;
|
||||
return res.json();
|
||||
// Server-side uses PUBLIC_API_BASE (e.g. http://localhost:8000).
|
||||
// Browser-side uses /api so nginx proxies the request on the correct host.
|
||||
const base = browser ? "/api" : PUBLIC_API_BASE;
|
||||
const url = `${base}${path}`;
|
||||
const res = await fetch(url, {
|
||||
headers: { "Content-Type": "application/json", ...init.headers },
|
||||
...init,
|
||||
});
|
||||
if (!res.ok) {
|
||||
const detail = await res.json().catch(() => ({ detail: res.statusText }));
|
||||
throw new Error(detail?.detail ?? res.statusText);
|
||||
}
|
||||
if (res.status === 204) return undefined as T;
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(path: string) => request<T>(path),
|
||||
post: <T>(path: string, body: unknown) =>
|
||||
request<T>(path, { method: 'POST', body: JSON.stringify(body) }),
|
||||
patch: <T>(path: string, body: unknown) =>
|
||||
request<T>(path, { method: 'PATCH', body: JSON.stringify(body) }),
|
||||
del: (path: string) => request<void>(path, { method: 'DELETE' })
|
||||
get: <T>(path: string) => request<T>(path),
|
||||
post: <T>(path: string, body: unknown) =>
|
||||
request<T>(path, { method: "POST", body: JSON.stringify(body) }),
|
||||
patch: <T>(path: string, body: unknown) =>
|
||||
request<T>(path, { method: "PATCH", body: JSON.stringify(body) }),
|
||||
del: (path: string) => request<void>(path, { method: "DELETE" }),
|
||||
};
|
||||
|
||||
// ─── Products ────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface ProductListParams {
|
||||
category?: string;
|
||||
brand?: string;
|
||||
targets?: string[];
|
||||
is_medication?: boolean;
|
||||
is_tool?: boolean;
|
||||
category?: string;
|
||||
brand?: string;
|
||||
targets?: string[];
|
||||
is_medication?: boolean;
|
||||
is_tool?: boolean;
|
||||
}
|
||||
|
||||
export function getProducts(params: ProductListParams = {}): Promise<Product[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.category) q.set('category', params.category);
|
||||
if (params.brand) q.set('brand', params.brand);
|
||||
if (params.targets) params.targets.forEach((t) => q.append('targets', t));
|
||||
if (params.is_medication != null) 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 function getProducts(
|
||||
params: ProductListParams = {},
|
||||
): Promise<Product[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.category) q.set("category", params.category);
|
||||
if (params.brand) q.set("brand", params.brand);
|
||||
if (params.targets) params.targets.forEach((t) => q.append("targets", t));
|
||||
if (params.is_medication != null)
|
||||
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 createProduct = (body: Record<string, unknown>): Promise<Product> =>
|
||||
api.post('/products', body);
|
||||
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 getProduct = (id: string): Promise<Product> =>
|
||||
api.get(`/products/${id}`);
|
||||
export const createProduct = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<Product> => api.post("/products", body);
|
||||
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[]> =>
|
||||
api.get(`/products/${productId}/inventory`);
|
||||
api.get(`/products/${productId}/inventory`);
|
||||
export const createInventory = (
|
||||
productId: string,
|
||||
body: Record<string, unknown>
|
||||
): Promise<ProductInventory> => api.post(`/products/${productId}/inventory`, body);
|
||||
export const updateInventory = (id: string, body: Record<string, unknown>): Promise<ProductInventory> =>
|
||||
api.patch(`/inventory/${id}`, body);
|
||||
export const deleteInventory = (id: string): Promise<void> => api.del(`/inventory/${id}`);
|
||||
productId: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<ProductInventory> =>
|
||||
api.post(`/products/${productId}/inventory`, body);
|
||||
export const updateInventory = (
|
||||
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 {
|
||||
name?: string; brand?: string; line_name?: string; sku?: string; url?: string; barcode?: string;
|
||||
category?: string; recommended_time?: string; texture?: string; absorption_speed?: string;
|
||||
leave_on?: boolean; price_tier?: string;
|
||||
size_ml?: number; full_weight_g?: 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;
|
||||
name?: string;
|
||||
brand?: string;
|
||||
line_name?: string;
|
||||
sku?: string;
|
||||
url?: string;
|
||||
barcode?: string;
|
||||
category?: string;
|
||||
recommended_time?: string;
|
||||
texture?: string;
|
||||
absorption_speed?: string;
|
||||
leave_on?: boolean;
|
||||
price_tier?: string;
|
||||
size_ml?: number;
|
||||
full_weight_g?: 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> =>
|
||||
api.post('/products/parse-text', { text });
|
||||
api.post("/products/parse-text", { text });
|
||||
|
||||
// ─── Routines ────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface RoutineListParams {
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
part_of_day?: string;
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
part_of_day?: string;
|
||||
}
|
||||
|
||||
export function getRoutines(params: RoutineListParams = {}): Promise<Routine[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.from_date) q.set('from_date', params.from_date);
|
||||
if (params.to_date) q.set('to_date', params.to_date);
|
||||
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 function getRoutines(
|
||||
params: RoutineListParams = {},
|
||||
): Promise<Routine[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.from_date) q.set("from_date", params.from_date);
|
||||
if (params.to_date) q.set("to_date", params.to_date);
|
||||
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 createRoutine = (body: Record<string, unknown>): Promise<Routine> =>
|
||||
api.post('/routines', body);
|
||||
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 getRoutine = (id: string): Promise<Routine> =>
|
||||
api.get(`/routines/${id}`);
|
||||
export const createRoutine = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<Routine> => api.post("/routines", body);
|
||||
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> =>
|
||||
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 addRoutineStep = (
|
||||
routineId: string,
|
||||
body: Record<string, unknown>,
|
||||
): 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> =>
|
||||
api.del(`/routines/steps/${stepId}`);
|
||||
api.del(`/routines/steps/${stepId}`);
|
||||
|
||||
export const suggestRoutine = (body: {
|
||||
routine_date: string;
|
||||
part_of_day: PartOfDay;
|
||||
notes?: string;
|
||||
include_minoxidil_beard?: boolean;
|
||||
leaving_home?: boolean;
|
||||
}): Promise<RoutineSuggestion> => api.post('/routines/suggest', body);
|
||||
routine_date: string;
|
||||
part_of_day: PartOfDay;
|
||||
notes?: string;
|
||||
include_minoxidil_beard?: boolean;
|
||||
leaving_home?: boolean;
|
||||
}): Promise<RoutineSuggestion> => api.post("/routines/suggest", body);
|
||||
|
||||
export const suggestBatch = (body: {
|
||||
from_date: string;
|
||||
to_date: string;
|
||||
notes?: string;
|
||||
include_minoxidil_beard?: boolean;
|
||||
minimize_products?: boolean;
|
||||
}): Promise<BatchSuggestion> => api.post('/routines/suggest-batch', body);
|
||||
from_date: string;
|
||||
to_date: string;
|
||||
notes?: string;
|
||||
include_minoxidil_beard?: boolean;
|
||||
minimize_products?: boolean;
|
||||
}): Promise<BatchSuggestion> => api.post("/routines/suggest-batch", body);
|
||||
|
||||
export const getGroomingSchedule = (): Promise<GroomingSchedule[]> =>
|
||||
api.get('/routines/grooming-schedule');
|
||||
export const createGroomingScheduleEntry = (body: Record<string, unknown>): Promise<GroomingSchedule> =>
|
||||
api.post('/routines/grooming-schedule', body);
|
||||
export const updateGroomingScheduleEntry = (id: string, body: Record<string, unknown>): Promise<GroomingSchedule> =>
|
||||
api.patch(`/routines/grooming-schedule/${id}`, body);
|
||||
api.get("/routines/grooming-schedule");
|
||||
export const createGroomingScheduleEntry = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<GroomingSchedule> => api.post("/routines/grooming-schedule", 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> =>
|
||||
api.del(`/routines/grooming-schedule/${id}`);
|
||||
api.del(`/routines/grooming-schedule/${id}`);
|
||||
|
||||
// ─── Health – Medications ────────────────────────────────────────────────────
|
||||
|
||||
export interface MedicationListParams {
|
||||
kind?: string;
|
||||
product_name?: string;
|
||||
kind?: string;
|
||||
product_name?: string;
|
||||
}
|
||||
|
||||
export function getMedications(params: MedicationListParams = {}): Promise<MedicationEntry[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.kind) q.set('kind', params.kind);
|
||||
if (params.product_name) q.set('product_name', params.product_name);
|
||||
const qs = q.toString();
|
||||
return api.get(`/health/medications${qs ? `?${qs}` : ''}`);
|
||||
export function getMedications(
|
||||
params: MedicationListParams = {},
|
||||
): Promise<MedicationEntry[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.kind) q.set("kind", params.kind);
|
||||
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> =>
|
||||
api.get(`/health/medications/${id}`);
|
||||
export const createMedication = (body: Record<string, unknown>): Promise<MedicationEntry> =>
|
||||
api.post('/health/medications', body);
|
||||
api.get(`/health/medications/${id}`);
|
||||
export const createMedication = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<MedicationEntry> => api.post("/health/medications", body);
|
||||
export const updateMedication = (
|
||||
id: string,
|
||||
body: Record<string, unknown>
|
||||
id: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<MedicationEntry> => api.patch(`/health/medications/${id}`, body);
|
||||
export const deleteMedication = (id: string): Promise<void> =>
|
||||
api.del(`/health/medications/${id}`);
|
||||
api.del(`/health/medications/${id}`);
|
||||
|
||||
export const getMedicationUsages = (medicationId: string): Promise<MedicationUsage[]> =>
|
||||
api.get(`/health/medications/${medicationId}/usages`);
|
||||
export const getMedicationUsages = (
|
||||
medicationId: string,
|
||||
): Promise<MedicationUsage[]> =>
|
||||
api.get(`/health/medications/${medicationId}/usages`);
|
||||
export const createMedicationUsage = (
|
||||
medicationId: string,
|
||||
body: Record<string, unknown>
|
||||
): Promise<MedicationUsage> => api.post(`/health/medications/${medicationId}/usages`, body);
|
||||
medicationId: string,
|
||||
body: Record<string, unknown>,
|
||||
): Promise<MedicationUsage> =>
|
||||
api.post(`/health/medications/${medicationId}/usages`, body);
|
||||
|
||||
// ─── Health – Lab results ────────────────────────────────────────────────────
|
||||
|
||||
export interface LabResultListParams {
|
||||
test_code?: string;
|
||||
flag?: string;
|
||||
lab?: string;
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
test_code?: string;
|
||||
flag?: string;
|
||||
lab?: string;
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
}
|
||||
|
||||
export function getLabResults(params: LabResultListParams = {}): Promise<LabResult[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.test_code) q.set('test_code', params.test_code);
|
||||
if (params.flag) q.set('flag', params.flag);
|
||||
if (params.lab) q.set('lab', params.lab);
|
||||
if (params.from_date) q.set('from_date', params.from_date);
|
||||
if (params.to_date) q.set('to_date', params.to_date);
|
||||
const qs = q.toString();
|
||||
return api.get(`/health/lab-results${qs ? `?${qs}` : ''}`);
|
||||
export function getLabResults(
|
||||
params: LabResultListParams = {},
|
||||
): Promise<LabResult[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.test_code) q.set("test_code", params.test_code);
|
||||
if (params.flag) q.set("flag", params.flag);
|
||||
if (params.lab) q.set("lab", params.lab);
|
||||
if (params.from_date) q.set("from_date", params.from_date);
|
||||
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> =>
|
||||
api.get(`/health/lab-results/${id}`);
|
||||
export const createLabResult = (body: Record<string, unknown>): Promise<LabResult> =>
|
||||
api.post('/health/lab-results', body);
|
||||
export const updateLabResult = (id: string, body: Record<string, unknown>): Promise<LabResult> =>
|
||||
api.patch(`/health/lab-results/${id}`, body);
|
||||
api.get(`/health/lab-results/${id}`);
|
||||
export const createLabResult = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<LabResult> => api.post("/health/lab-results", 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> =>
|
||||
api.del(`/health/lab-results/${id}`);
|
||||
api.del(`/health/lab-results/${id}`);
|
||||
|
||||
// ─── Skin ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface SnapshotListParams {
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
overall_state?: string;
|
||||
from_date?: string;
|
||||
to_date?: string;
|
||||
overall_state?: string;
|
||||
}
|
||||
|
||||
export function getSkinSnapshots(params: SnapshotListParams = {}): Promise<SkinConditionSnapshot[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.from_date) q.set('from_date', params.from_date);
|
||||
if (params.to_date) q.set('to_date', params.to_date);
|
||||
if (params.overall_state) q.set('overall_state', params.overall_state);
|
||||
const qs = q.toString();
|
||||
return api.get(`/skincare${qs ? `?${qs}` : ''}`);
|
||||
export function getSkinSnapshots(
|
||||
params: SnapshotListParams = {},
|
||||
): Promise<SkinConditionSnapshot[]> {
|
||||
const q = new URLSearchParams();
|
||||
if (params.from_date) q.set("from_date", params.from_date);
|
||||
if (params.to_date) q.set("to_date", params.to_date);
|
||||
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> =>
|
||||
api.get(`/skincare/${id}`);
|
||||
export const createSkinSnapshot = (body: Record<string, unknown>): Promise<SkinConditionSnapshot> =>
|
||||
api.post('/skincare', body);
|
||||
api.get(`/skincare/${id}`);
|
||||
export const createSkinSnapshot = (
|
||||
body: Record<string, unknown>,
|
||||
): Promise<SkinConditionSnapshot> => api.post("/skincare", body);
|
||||
export const updateSkinSnapshot = (
|
||||
id: string,
|
||||
body: Record<string, unknown>
|
||||
id: string,
|
||||
body: Record<string, unknown>,
|
||||
): 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 {
|
||||
overall_state?: string;
|
||||
texture?: string;
|
||||
skin_type?: string;
|
||||
hydration_level?: number;
|
||||
sebum_tzone?: number;
|
||||
sebum_cheeks?: number;
|
||||
sensitivity_level?: number;
|
||||
barrier_state?: string;
|
||||
active_concerns?: string[];
|
||||
risks?: string[];
|
||||
priorities?: string[];
|
||||
notes?: string;
|
||||
overall_state?: string;
|
||||
texture?: string;
|
||||
skin_type?: string;
|
||||
hydration_level?: number;
|
||||
sebum_tzone?: number;
|
||||
sebum_cheeks?: number;
|
||||
sensitivity_level?: number;
|
||||
barrier_state?: string;
|
||||
active_concerns?: string[];
|
||||
risks?: string[];
|
||||
priorities?: string[];
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export async function analyzeSkinPhotos(files: File[]): Promise<SkinPhotoAnalysisResponse> {
|
||||
const body = new FormData();
|
||||
for (const file of files) body.append('photos', file);
|
||||
const base = browser ? '/api' : PUBLIC_API_BASE;
|
||||
const res = await fetch(`${base}/skincare/analyze-photos`, { method: 'POST', body });
|
||||
if (!res.ok) {
|
||||
const detail = await res.json().catch(() => ({ detail: res.statusText }));
|
||||
throw new Error(detail?.detail ?? res.statusText);
|
||||
}
|
||||
return res.json();
|
||||
export async function analyzeSkinPhotos(
|
||||
files: File[],
|
||||
): Promise<SkinPhotoAnalysisResponse> {
|
||||
const body = new FormData();
|
||||
for (const file of files) body.append("photos", file);
|
||||
const base = browser ? "/api" : PUBLIC_API_BASE;
|
||||
const res = await fetch(`${base}/skincare/analyze-photos`, {
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
if (!res.ok) {
|
||||
const detail = await res.json().catch(() => ({ detail: res.statusText }));
|
||||
throw new Error(detail?.detail ?? res.statusText);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import Root, {
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
buttonVariants,
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
buttonVariants,
|
||||
} from "./button.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
type ButtonProps as Props,
|
||||
//
|
||||
Root as Button,
|
||||
buttonVariants,
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
Root,
|
||||
type ButtonProps as Props,
|
||||
//
|
||||
Root as Button,
|
||||
buttonVariants,
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ import Title from "./card-title.svelte";
|
|||
import Action from "./card-action.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
Description,
|
||||
Footer,
|
||||
Header,
|
||||
Title,
|
||||
Action,
|
||||
//
|
||||
Root as Card,
|
||||
Content as CardContent,
|
||||
Description as CardDescription,
|
||||
Footer as CardFooter,
|
||||
Header as CardHeader,
|
||||
Title as CardTitle,
|
||||
Action as CardAction,
|
||||
Root,
|
||||
Content,
|
||||
Description,
|
||||
Footer,
|
||||
Header,
|
||||
Title,
|
||||
Action,
|
||||
//
|
||||
Root as Card,
|
||||
Content as CardContent,
|
||||
Description as CardDescription,
|
||||
Footer as CardFooter,
|
||||
Header as CardHeader,
|
||||
Title as CardTitle,
|
||||
Action as CardAction,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Root from "./input.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Input,
|
||||
Root,
|
||||
//
|
||||
Root as Input,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Root from "./label.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Label,
|
||||
Root,
|
||||
//
|
||||
Root as Label,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,27 +11,27 @@ import GroupHeading from "./select-group-heading.svelte";
|
|||
import Portal from "./select-portal.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Group,
|
||||
Label,
|
||||
Item,
|
||||
Content,
|
||||
Trigger,
|
||||
Separator,
|
||||
ScrollDownButton,
|
||||
ScrollUpButton,
|
||||
GroupHeading,
|
||||
Portal,
|
||||
//
|
||||
Root as Select,
|
||||
Group as SelectGroup,
|
||||
Label as SelectLabel,
|
||||
Item as SelectItem,
|
||||
Content as SelectContent,
|
||||
Trigger as SelectTrigger,
|
||||
Separator as SelectSeparator,
|
||||
ScrollDownButton as SelectScrollDownButton,
|
||||
ScrollUpButton as SelectScrollUpButton,
|
||||
GroupHeading as SelectGroupHeading,
|
||||
Portal as SelectPortal,
|
||||
Root,
|
||||
Group,
|
||||
Label,
|
||||
Item,
|
||||
Content,
|
||||
Trigger,
|
||||
Separator,
|
||||
ScrollDownButton,
|
||||
ScrollUpButton,
|
||||
GroupHeading,
|
||||
Portal,
|
||||
//
|
||||
Root as Select,
|
||||
Group as SelectGroup,
|
||||
Label as SelectLabel,
|
||||
Item as SelectItem,
|
||||
Content as SelectContent,
|
||||
Trigger as SelectTrigger,
|
||||
Separator as SelectSeparator,
|
||||
ScrollDownButton as SelectScrollDownButton,
|
||||
ScrollUpButton as SelectScrollUpButton,
|
||||
GroupHeading as SelectGroupHeading,
|
||||
Portal as SelectPortal,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Root from "./separator.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Separator,
|
||||
Root,
|
||||
//
|
||||
Root as Separator,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,21 +8,21 @@ import Header from "./table-header.svelte";
|
|||
import Row from "./table-row.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Body,
|
||||
Caption,
|
||||
Cell,
|
||||
Footer,
|
||||
Head,
|
||||
Header,
|
||||
Row,
|
||||
//
|
||||
Root as Table,
|
||||
Body as TableBody,
|
||||
Caption as TableCaption,
|
||||
Cell as TableCell,
|
||||
Footer as TableFooter,
|
||||
Head as TableHead,
|
||||
Header as TableHeader,
|
||||
Row as TableRow,
|
||||
Root,
|
||||
Body,
|
||||
Caption,
|
||||
Cell,
|
||||
Footer,
|
||||
Head,
|
||||
Header,
|
||||
Row,
|
||||
//
|
||||
Root as Table,
|
||||
Body as TableBody,
|
||||
Caption as TableCaption,
|
||||
Cell as TableCell,
|
||||
Footer as TableFooter,
|
||||
Head as TableHead,
|
||||
Header as TableHeader,
|
||||
Row as TableRow,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import List from "./tabs-list.svelte";
|
|||
import Trigger from "./tabs-trigger.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
List,
|
||||
Trigger,
|
||||
//
|
||||
Root as Tabs,
|
||||
Content as TabsContent,
|
||||
List as TabsList,
|
||||
Trigger as TabsTrigger,
|
||||
Root,
|
||||
Content,
|
||||
List,
|
||||
Trigger,
|
||||
//
|
||||
Root as Tabs,
|
||||
Content as TabsContent,
|
||||
List as TabsList,
|
||||
Trigger as TabsTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,308 +1,335 @@
|
|||
// ─── Enums ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export type AbsorptionSpeed = 'very_fast' | 'fast' | '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 AbsorptionSpeed =
|
||||
| "very_fast"
|
||||
| "fast"
|
||||
| "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 =
|
||||
| 'humectant'
|
||||
| 'emollient'
|
||||
| 'occlusive'
|
||||
| 'exfoliant_aha'
|
||||
| 'exfoliant_bha'
|
||||
| 'exfoliant_pha'
|
||||
| 'retinoid'
|
||||
| 'antioxidant'
|
||||
| 'soothing'
|
||||
| 'barrier_support'
|
||||
| 'brightening'
|
||||
| 'anti_acne'
|
||||
| 'ceramide'
|
||||
| 'niacinamide'
|
||||
| 'sunscreen'
|
||||
| 'peptide'
|
||||
| 'hair_growth_stimulant'
|
||||
| 'prebiotic'
|
||||
| 'vitamin_c'
|
||||
| 'anti_aging';
|
||||
export type InteractionScope = 'same_step' | 'same_day' | 'same_period';
|
||||
export type MedicationKind = 'prescription' | 'otc' | 'supplement' | 'herbal' | 'other';
|
||||
export type OverallSkinState = 'excellent' | 'good' | 'fair' | 'poor';
|
||||
export type PartOfDay = 'am' | 'pm';
|
||||
export type PriceTier = 'budget' | 'mid' | 'premium' | 'luxury';
|
||||
| "humectant"
|
||||
| "emollient"
|
||||
| "occlusive"
|
||||
| "exfoliant_aha"
|
||||
| "exfoliant_bha"
|
||||
| "exfoliant_pha"
|
||||
| "retinoid"
|
||||
| "antioxidant"
|
||||
| "soothing"
|
||||
| "barrier_support"
|
||||
| "brightening"
|
||||
| "anti_acne"
|
||||
| "ceramide"
|
||||
| "niacinamide"
|
||||
| "sunscreen"
|
||||
| "peptide"
|
||||
| "hair_growth_stimulant"
|
||||
| "prebiotic"
|
||||
| "vitamin_c"
|
||||
| "anti_aging";
|
||||
export type InteractionScope = "same_step" | "same_day" | "same_period";
|
||||
export type MedicationKind =
|
||||
| "prescription"
|
||||
| "otc"
|
||||
| "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 =
|
||||
| 'cleanser'
|
||||
| 'toner'
|
||||
| 'essence'
|
||||
| 'serum'
|
||||
| 'moisturizer'
|
||||
| 'spf'
|
||||
| 'mask'
|
||||
| 'exfoliant'
|
||||
| 'hair_treatment'
|
||||
| 'tool'
|
||||
| 'spot_treatment'
|
||||
| 'oil';
|
||||
export type ResultFlag = 'N' | 'ABN' | 'POS' | 'NEG' | 'L' | 'H';
|
||||
| "cleanser"
|
||||
| "toner"
|
||||
| "essence"
|
||||
| "serum"
|
||||
| "moisturizer"
|
||||
| "spf"
|
||||
| "mask"
|
||||
| "exfoliant"
|
||||
| "hair_treatment"
|
||||
| "tool"
|
||||
| "spot_treatment"
|
||||
| "oil";
|
||||
export type ResultFlag = "N" | "ABN" | "POS" | "NEG" | "L" | "H";
|
||||
export type SkinConcern =
|
||||
| 'acne'
|
||||
| 'rosacea'
|
||||
| 'hyperpigmentation'
|
||||
| 'aging'
|
||||
| 'dehydration'
|
||||
| 'redness'
|
||||
| 'damaged_barrier'
|
||||
| 'pore_visibility'
|
||||
| 'uneven_texture'
|
||||
| 'hair_growth'
|
||||
| 'sebum_excess';
|
||||
export type SkinTexture = 'smooth' | 'rough' | 'flaky' | 'bumpy';
|
||||
export type SkinType = 'dry' | 'oily' | 'combination' | 'sensitive' | 'normal' | 'acne_prone';
|
||||
| "acne"
|
||||
| "rosacea"
|
||||
| "hyperpigmentation"
|
||||
| "aging"
|
||||
| "dehydration"
|
||||
| "redness"
|
||||
| "damaged_barrier"
|
||||
| "pore_visibility"
|
||||
| "uneven_texture"
|
||||
| "hair_growth"
|
||||
| "sebum_excess";
|
||||
export type SkinTexture = "smooth" | "rough" | "flaky" | "bumpy";
|
||||
export type SkinType =
|
||||
| "dry"
|
||||
| "oily"
|
||||
| "combination"
|
||||
| "sensitive"
|
||||
| "normal"
|
||||
| "acne_prone";
|
||||
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 ───────────────────────────────────────────────────────────
|
||||
|
||||
export interface ActiveIngredient {
|
||||
name: string;
|
||||
percent?: number;
|
||||
functions: IngredientFunction[];
|
||||
strength_level?: StrengthLevel;
|
||||
irritation_potential?: StrengthLevel;
|
||||
name: string;
|
||||
percent?: number;
|
||||
functions: IngredientFunction[];
|
||||
strength_level?: StrengthLevel;
|
||||
irritation_potential?: StrengthLevel;
|
||||
}
|
||||
|
||||
export interface ProductEffectProfile {
|
||||
hydration_immediate: number;
|
||||
hydration_long_term: number;
|
||||
barrier_repair_strength: number;
|
||||
soothing_strength: number;
|
||||
exfoliation_strength: number;
|
||||
retinoid_strength: number;
|
||||
irritation_risk: number;
|
||||
comedogenic_risk: number;
|
||||
barrier_disruption_risk: number;
|
||||
dryness_risk: number;
|
||||
brightening_strength: number;
|
||||
anti_acne_strength: number;
|
||||
anti_aging_strength: number;
|
||||
hydration_immediate: number;
|
||||
hydration_long_term: number;
|
||||
barrier_repair_strength: number;
|
||||
soothing_strength: number;
|
||||
exfoliation_strength: number;
|
||||
retinoid_strength: number;
|
||||
irritation_risk: number;
|
||||
comedogenic_risk: number;
|
||||
barrier_disruption_risk: number;
|
||||
dryness_risk: number;
|
||||
brightening_strength: number;
|
||||
anti_acne_strength: number;
|
||||
anti_aging_strength: number;
|
||||
}
|
||||
|
||||
export interface ProductInteraction {
|
||||
target: string;
|
||||
scope: InteractionScope;
|
||||
reason?: string;
|
||||
target: string;
|
||||
scope: InteractionScope;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface ProductContext {
|
||||
safe_after_shaving?: boolean;
|
||||
safe_after_acids?: boolean;
|
||||
safe_after_retinoids?: boolean;
|
||||
safe_with_compromised_barrier?: boolean;
|
||||
low_uv_only?: boolean;
|
||||
safe_after_shaving?: boolean;
|
||||
safe_after_acids?: boolean;
|
||||
safe_after_retinoids?: boolean;
|
||||
safe_with_compromised_barrier?: boolean;
|
||||
low_uv_only?: boolean;
|
||||
}
|
||||
|
||||
export interface ProductInventory {
|
||||
id: string;
|
||||
product_id: string;
|
||||
is_opened: boolean;
|
||||
opened_at?: string;
|
||||
finished_at?: string;
|
||||
expiry_date?: string;
|
||||
current_weight_g?: number;
|
||||
last_weighed_at?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
product?: Product;
|
||||
id: string;
|
||||
product_id: string;
|
||||
is_opened: boolean;
|
||||
opened_at?: string;
|
||||
finished_at?: string;
|
||||
expiry_date?: string;
|
||||
current_weight_g?: number;
|
||||
last_weighed_at?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
product?: Product;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
id: string;
|
||||
name: string;
|
||||
brand: string;
|
||||
line_name?: string;
|
||||
sku?: string;
|
||||
url?: string;
|
||||
barcode?: string;
|
||||
category: ProductCategory;
|
||||
recommended_time: DayTime;
|
||||
texture?: TextureType;
|
||||
absorption_speed?: AbsorptionSpeed;
|
||||
leave_on: boolean;
|
||||
price_tier?: PriceTier;
|
||||
size_ml?: number;
|
||||
full_weight_g?: number;
|
||||
empty_weight_g?: number;
|
||||
pao_months?: number;
|
||||
inci: string[];
|
||||
actives?: ActiveIngredient[];
|
||||
recommended_for: SkinType[];
|
||||
targets: SkinConcern[];
|
||||
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;
|
||||
personal_tolerance_notes?: string;
|
||||
personal_repurchase_intent?: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
inventory: ProductInventory[];
|
||||
id: string;
|
||||
name: string;
|
||||
brand: string;
|
||||
line_name?: string;
|
||||
sku?: string;
|
||||
url?: string;
|
||||
barcode?: string;
|
||||
category: ProductCategory;
|
||||
recommended_time: DayTime;
|
||||
texture?: TextureType;
|
||||
absorption_speed?: AbsorptionSpeed;
|
||||
leave_on: boolean;
|
||||
price_tier?: PriceTier;
|
||||
size_ml?: number;
|
||||
full_weight_g?: number;
|
||||
empty_weight_g?: number;
|
||||
pao_months?: number;
|
||||
inci: string[];
|
||||
actives?: ActiveIngredient[];
|
||||
recommended_for: SkinType[];
|
||||
targets: SkinConcern[];
|
||||
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;
|
||||
personal_tolerance_notes?: string;
|
||||
personal_repurchase_intent?: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
inventory: ProductInventory[];
|
||||
}
|
||||
|
||||
// ─── Routine types ───────────────────────────────────────────────────────────
|
||||
|
||||
export interface RoutineStep {
|
||||
id: string;
|
||||
routine_id: string;
|
||||
product_id?: string;
|
||||
order_index: number;
|
||||
action_type?: GroomingAction;
|
||||
action_notes?: string;
|
||||
dose?: string;
|
||||
region?: string;
|
||||
product?: Product;
|
||||
id: string;
|
||||
routine_id: string;
|
||||
product_id?: string;
|
||||
order_index: number;
|
||||
action_type?: GroomingAction;
|
||||
action_notes?: string;
|
||||
dose?: string;
|
||||
region?: string;
|
||||
product?: Product;
|
||||
}
|
||||
|
||||
export interface Routine {
|
||||
id: string;
|
||||
routine_date: string;
|
||||
part_of_day: PartOfDay;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
steps?: RoutineStep[];
|
||||
id: string;
|
||||
routine_date: string;
|
||||
part_of_day: PartOfDay;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
steps?: RoutineStep[];
|
||||
}
|
||||
|
||||
export interface GroomingSchedule {
|
||||
id: string;
|
||||
day_of_week: number;
|
||||
action: GroomingAction;
|
||||
notes?: string;
|
||||
id: string;
|
||||
day_of_week: number;
|
||||
action: GroomingAction;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface SuggestedStep {
|
||||
product_id?: string;
|
||||
action_type?: GroomingAction;
|
||||
action_notes?: string;
|
||||
dose?: string;
|
||||
region?: string;
|
||||
product_id?: string;
|
||||
action_type?: GroomingAction;
|
||||
action_notes?: string;
|
||||
dose?: string;
|
||||
region?: string;
|
||||
}
|
||||
|
||||
export interface RoutineSuggestion {
|
||||
steps: SuggestedStep[];
|
||||
reasoning: string;
|
||||
steps: SuggestedStep[];
|
||||
reasoning: string;
|
||||
}
|
||||
|
||||
export interface DayPlan {
|
||||
date: string;
|
||||
am_steps: SuggestedStep[];
|
||||
pm_steps: SuggestedStep[];
|
||||
reasoning: string;
|
||||
date: string;
|
||||
am_steps: SuggestedStep[];
|
||||
pm_steps: SuggestedStep[];
|
||||
reasoning: string;
|
||||
}
|
||||
|
||||
export interface BatchSuggestion {
|
||||
days: DayPlan[];
|
||||
overall_reasoning: string;
|
||||
days: DayPlan[];
|
||||
overall_reasoning: string;
|
||||
}
|
||||
|
||||
// ─── Shopping suggestion types ───────────────────────────────────────────────
|
||||
|
||||
export interface ProductSuggestion {
|
||||
category: string;
|
||||
product_type: string;
|
||||
key_ingredients: string[];
|
||||
target_concerns: string[];
|
||||
why_needed: string;
|
||||
recommended_time: string;
|
||||
frequency: string;
|
||||
category: string;
|
||||
product_type: string;
|
||||
key_ingredients: string[];
|
||||
target_concerns: string[];
|
||||
why_needed: string;
|
||||
recommended_time: string;
|
||||
frequency: string;
|
||||
}
|
||||
|
||||
export interface ShoppingSuggestionResponse {
|
||||
suggestions: ProductSuggestion[];
|
||||
reasoning: string;
|
||||
suggestions: ProductSuggestion[];
|
||||
reasoning: string;
|
||||
}
|
||||
|
||||
// ─── Health types ────────────────────────────────────────────────────────────
|
||||
|
||||
export interface MedicationUsage {
|
||||
record_id: string;
|
||||
medication_record_id: string;
|
||||
dose_value?: number;
|
||||
dose_unit?: string;
|
||||
frequency?: string;
|
||||
schedule_text?: string;
|
||||
as_needed: boolean;
|
||||
valid_from: string;
|
||||
valid_to?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
record_id: string;
|
||||
medication_record_id: string;
|
||||
dose_value?: number;
|
||||
dose_unit?: string;
|
||||
frequency?: string;
|
||||
schedule_text?: string;
|
||||
as_needed: boolean;
|
||||
valid_from: string;
|
||||
valid_to?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface MedicationEntry {
|
||||
record_id: string;
|
||||
kind: MedicationKind;
|
||||
product_name: string;
|
||||
active_substance?: string;
|
||||
formulation?: string;
|
||||
route?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
usage_history: MedicationUsage[];
|
||||
record_id: string;
|
||||
kind: MedicationKind;
|
||||
product_name: string;
|
||||
active_substance?: string;
|
||||
formulation?: string;
|
||||
route?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
usage_history: MedicationUsage[];
|
||||
}
|
||||
|
||||
export interface LabResult {
|
||||
record_id: string;
|
||||
collected_at: string;
|
||||
test_code: string;
|
||||
test_name_original?: string;
|
||||
test_name_loinc?: string;
|
||||
value_num?: number;
|
||||
value_text?: string;
|
||||
value_bool?: boolean;
|
||||
unit_original?: string;
|
||||
unit_ucum?: string;
|
||||
ref_low?: number;
|
||||
ref_high?: number;
|
||||
ref_text?: string;
|
||||
flag?: ResultFlag;
|
||||
lab?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
record_id: string;
|
||||
collected_at: string;
|
||||
test_code: string;
|
||||
test_name_original?: string;
|
||||
test_name_loinc?: string;
|
||||
value_num?: number;
|
||||
value_text?: string;
|
||||
value_bool?: boolean;
|
||||
unit_original?: string;
|
||||
unit_ucum?: string;
|
||||
ref_low?: number;
|
||||
ref_high?: number;
|
||||
ref_text?: string;
|
||||
flag?: ResultFlag;
|
||||
lab?: string;
|
||||
source_file?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ─── Skin types ──────────────────────────────────────────────────────────────
|
||||
|
||||
export interface SkinConditionSnapshot {
|
||||
id: string;
|
||||
snapshot_date: string;
|
||||
overall_state?: OverallSkinState;
|
||||
skin_type?: SkinType;
|
||||
texture?: SkinTexture;
|
||||
hydration_level?: number;
|
||||
sebum_tzone?: number;
|
||||
sebum_cheeks?: number;
|
||||
sensitivity_level?: number;
|
||||
barrier_state?: BarrierState;
|
||||
active_concerns: SkinConcern[];
|
||||
risks: string[];
|
||||
priorities: string[];
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
id: string;
|
||||
snapshot_date: string;
|
||||
overall_state?: OverallSkinState;
|
||||
skin_type?: SkinType;
|
||||
texture?: SkinTexture;
|
||||
hydration_level?: number;
|
||||
sebum_tzone?: number;
|
||||
sebum_cheeks?: number;
|
||||
sensitivity_level?: number;
|
||||
barrier_state?: BarrierState;
|
||||
active_concerns: SkinConcern[];
|
||||
risks: string[];
|
||||
priorities: string[];
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue