feat: Sprint 4 complete — frontend MVP (admin dashboard + member portal)
Shadboard starter-kit (Next.js 15 + React 19 + shadcn/ui + Tailwind 4) Sprint 4.a — Admin Dashboard: - Auth: NextAuth.js v5, login page, middleware, token rotation - Dashboard: KPI cards, Recharts stock chart, quick actions - Members: TanStack Table (search/sort/paginate), add/edit forms - Distributions: multi-step form, real-time quota check, history - Stock: batch management, recall dialog, bar chart - Reports: monthly/member-list/recall, PDF/CSV download, preview Sprint 4.b — Member Portal: - Separate route group with top-nav layout (mobile-first) - Quota dashboard with radial SVG progress indicators - Distribution history with month filter - Profile/settings with password change Cross-cutting: - i18n: German (default) + English via next-intl - Dark + light mode (next-themes, user-togglable) - Playwright E2E tests (6/6 green) - Docker multi-stage build (node:22-alpine) - API proxy via Next.js rewrites Tech: Next.js 15.2.8, React 19, Tailwind 4, NextAuth v5, TanStack Table, Recharts, Zod, React Hook Form, Playwright
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"common": {
|
||||
"appName": "CannaManage",
|
||||
"loading": "Laden...",
|
||||
"save": "Speichern",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen",
|
||||
"edit": "Bearbeiten",
|
||||
"create": "Erstellen",
|
||||
"search": "Suchen",
|
||||
"filter": "Filtern",
|
||||
"export": "Exportieren",
|
||||
"back": "Zurück",
|
||||
"next": "Weiter",
|
||||
"confirm": "Bestätigen",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"noData": "Keine Daten vorhanden"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
"members": "Mitglieder",
|
||||
"stock": "Bestand",
|
||||
"distributions": "Ausgaben",
|
||||
"compliance": "Compliance",
|
||||
"reports": "Berichte",
|
||||
"settings": "Einstellungen",
|
||||
"staff": "Personal",
|
||||
"portal": "Mitgliederportal"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"email": "E-Mail-Adresse",
|
||||
"password": "Passwort",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"resetPassword": "Passwort zurücksetzen",
|
||||
"loginButton": "Anmelden",
|
||||
"loggingIn": "Wird angemeldet...",
|
||||
"loginSubtitle": "Melde dich bei deinem Anbauverein an",
|
||||
"invalidCredentials": "Ungültige E-Mail-Adresse oder Passwort.",
|
||||
"networkError": "Verbindungsfehler. Bitte versuche es erneut.",
|
||||
"sessionExpired": "Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.",
|
||||
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
|
||||
"passwordRequired": "Bitte gib dein Passwort ein.",
|
||||
"passwordTooShort": "Passwort muss mindestens 8 Zeichen lang sein.",
|
||||
"footerText": "Sichere Verwaltung für deinen Cannabis-Anbauverein"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"activeMembers": "Aktive Mitglieder",
|
||||
"distributionsToday": "Ausgaben heute",
|
||||
"stockLevel": "Lagerbestand",
|
||||
"monthlyQuota": "Monatliches Kontingent",
|
||||
"quickActions": "Schnellaktionen",
|
||||
"newDistribution": "Neue Ausgabe",
|
||||
"addMember": "Mitglied hinzufügen",
|
||||
"recentDistributions": "Letzte Ausgaben",
|
||||
"stockByStrain": "Bestand nach Sorte",
|
||||
"date": "Datum",
|
||||
"member": "Mitglied",
|
||||
"strain": "Sorte",
|
||||
"amount": "Menge (g)",
|
||||
"staff": "Personal",
|
||||
"grams": "g",
|
||||
"today": "Heute",
|
||||
"trend": "+{value}% ggü. Vormonat",
|
||||
"quotaUsed": "{value}% verbraucht",
|
||||
"distributionCount": "{count} Ausgaben, {grams}g"
|
||||
},
|
||||
"members": {
|
||||
"title": "Mitgliederverwaltung",
|
||||
"addMember": "Mitglied hinzufügen",
|
||||
"name": "Name",
|
||||
"email": "E-Mail",
|
||||
"status": "Status",
|
||||
"memberSince": "Mitglied seit",
|
||||
"quota": "Kontingent",
|
||||
"actions": "Aktionen",
|
||||
"edit": "Bearbeiten",
|
||||
"active": "Aktiv",
|
||||
"suspended": "Gesperrt",
|
||||
"expelled": "Ausgeschlossen",
|
||||
"back": "Zurück zur Liste",
|
||||
"save": "Speichern",
|
||||
"create": "Mitglied anlegen",
|
||||
"firstName": "Vorname",
|
||||
"lastName": "Nachname",
|
||||
"dateOfBirth": "Geburtsdatum",
|
||||
"phone": "Telefon",
|
||||
"memberNumber": "Mitgliedsnummer",
|
||||
"joinedAt": "Beitrittsdatum",
|
||||
"notes": "Notizen",
|
||||
"notesPlaceholder": "Optionale Anmerkungen zum Mitglied...",
|
||||
"under21Warning": "Unter 21 — reduziertes Kontingent (30g/Monat)",
|
||||
"ageError": "Mitglieder müssen mindestens 18 Jahre alt sein.",
|
||||
"saved": "Änderungen gespeichert.",
|
||||
"created": "Mitglied erfolgreich angelegt.",
|
||||
"search": "Name oder E-Mail suchen...",
|
||||
"perPage": "Pro Seite",
|
||||
"showing": "{from}–{to} von {total}",
|
||||
"previous": "Zurück",
|
||||
"next": "Weiter",
|
||||
"noResults": "Keine Mitglieder gefunden.",
|
||||
"notFound": "Mitglied nicht gefunden.",
|
||||
"personalInfo": "Persönliche Daten",
|
||||
"membershipInfo": "Mitgliedschaft"
|
||||
},
|
||||
"stock": {
|
||||
"title": "Lager & Chargen",
|
||||
"newBatch": "Neue Charge",
|
||||
"stockOverview": "Bestandsübersicht",
|
||||
"batchId": "Chargen-ID",
|
||||
"strain": "Sorte",
|
||||
"thc": "THC %",
|
||||
"cbd": "CBD %",
|
||||
"status": "Status",
|
||||
"available": "Verfügbar",
|
||||
"availableGrams": "Verfügbar (g)",
|
||||
"receivedAt": "Eingangsdatum",
|
||||
"actions": "Aktionen",
|
||||
"statusAvailable": "Verfügbar",
|
||||
"statusRecalled": "Rückruf",
|
||||
"statusDepleted": "Aufgebraucht",
|
||||
"recall": "Rückruf",
|
||||
"recallConfirm": "Charge wirklich zurückrufen? Alle offenen Ausgaben mit dieser Charge werden blockiert.",
|
||||
"recallTitle": "Charge zurückrufen",
|
||||
"recallSuccess": "Charge zurückgerufen.",
|
||||
"totalBatches": "Chargen gesamt",
|
||||
"availableStock": "Verfügbarer Bestand",
|
||||
"recalledBatches": "Zurückgerufene Chargen",
|
||||
"strainCount": "Sorten",
|
||||
"filterAll": "Alle",
|
||||
"filterAvailable": "Nur verfügbar",
|
||||
"filterRecalled": "Nur Rückrufe",
|
||||
"addBatch": "Charge anlegen",
|
||||
"strainName": "Sortenname",
|
||||
"amount": "Menge (g)",
|
||||
"supplier": "Lieferant / Herkunft",
|
||||
"harvestDate": "Erntedatum",
|
||||
"notes": "Notizen",
|
||||
"notesPlaceholder": "Optionale Bemerkungen zur Charge...",
|
||||
"created": "Charge erfolgreich angelegt.",
|
||||
"grams": "g",
|
||||
"confirmRecall": "Rückruf bestätigen",
|
||||
"lowStock": "Niedrig"
|
||||
},
|
||||
"distributions": {
|
||||
"title": "Ausgaben",
|
||||
"newDistribution": "Neue Ausgabe",
|
||||
"todaySummary": "Heute: {count} Ausgaben, {grams}g verteilt",
|
||||
"dateTime": "Datum/Uhrzeit",
|
||||
"member": "Mitglied",
|
||||
"strain": "Sorte",
|
||||
"amount": "Menge (g)",
|
||||
"staff": "Personal",
|
||||
"status": "Status",
|
||||
"completed": "Abgeschlossen",
|
||||
"locked": "Gesperrt (unveränderbar)",
|
||||
"filterToday": "Heute",
|
||||
"filterWeek": "Diese Woche",
|
||||
"filterMonth": "Diesen Monat",
|
||||
"searchMember": "Mitglied suchen...",
|
||||
"step1": "Mitglied auswählen",
|
||||
"step2": "Kontingent prüfen",
|
||||
"step3": "Sorte & Menge",
|
||||
"step4": "Bestätigung",
|
||||
"selectMember": "Mitglied suchen (Name oder Nummer)...",
|
||||
"memberBlocked": "Mitglied ist gesperrt — keine Ausgabe möglich.",
|
||||
"under21Info": "Reduziertes Kontingent: 30g/Monat (unter 21)",
|
||||
"dailyRemaining": "Tagesrest",
|
||||
"monthlyRemaining": "Monatsrest",
|
||||
"selectBatch": "Charge auswählen",
|
||||
"available": "verfügbar",
|
||||
"amountLabel": "Menge in Gramm",
|
||||
"exceedsDaily": "Überschreitet das Tageslimit ({limit}g).",
|
||||
"exceedsMonthly": "Überschreitet das Monatslimit ({limit}g).",
|
||||
"exceedsBatch": "Nicht genügend Bestand in dieser Charge.",
|
||||
"confirm": "Ausgabe bestätigen",
|
||||
"summary": "Zusammenfassung",
|
||||
"success": "Ausgabe erfolgreich erfasst.",
|
||||
"grams": "g",
|
||||
"date": "Datum",
|
||||
"monthlyQuota": "Monatsquote",
|
||||
"remaining": "Verbleibend"
|
||||
},
|
||||
"reports": {
|
||||
"title": "Berichte",
|
||||
"monthly": "Monatsbericht",
|
||||
"monthlyDesc": "Übersicht aller Ausgaben im gewählten Monat, inkl. Mitglieder-Kontingente und Lagerveränderungen.",
|
||||
"memberList": "Mitgliederliste",
|
||||
"memberListDesc": "Vollständige Mitgliederliste mit Status, Kontingent-Auslastung und Kontaktdaten.",
|
||||
"recall": "Rückruf-Bericht",
|
||||
"recallDesc": "Alle Chargen mit Rückruf-Status und betroffene Ausgaben für Behörden-Meldung.",
|
||||
"downloadPdf": "Als PDF herunterladen",
|
||||
"downloadCsv": "Als CSV herunterladen",
|
||||
"preview": "Vorschau anzeigen",
|
||||
"generating": "Bericht wird generiert...",
|
||||
"downloaded": "{name} heruntergeladen.",
|
||||
"selectMonth": "Monat wählen",
|
||||
"selectStatus": "Status filtern",
|
||||
"allStatuses": "Alle",
|
||||
"activeOnly": "Aktiv",
|
||||
"suspendedOnly": "Gesperrt",
|
||||
"dateFrom": "Von",
|
||||
"dateTo": "Bis",
|
||||
"previewTitle": "Berichts-Vorschau",
|
||||
"totalDistributions": "Ausgaben gesamt",
|
||||
"totalGrams": "Gramm gesamt",
|
||||
"uniqueMembers": "Verschiedene Mitglieder",
|
||||
"averagePerMember": "Ø pro Mitglied",
|
||||
"topStrains": "Top-Sorten",
|
||||
"affectedDistributions": "Betroffene Ausgaben",
|
||||
"affectedMembers": "Betroffene Mitglieder",
|
||||
"recalledBatches": "Zurückgerufene Chargen",
|
||||
"close": "Schließen",
|
||||
"complianceNote": "Dieser Bericht ist für die Vorlage bei der zuständigen Behörde geeignet.",
|
||||
"complianceBadge": "§19 KCanG konform",
|
||||
"auditTrail": "Alle Berichte werden mit Zeitstempel generiert. Die zugrunde liegenden Ausgabe-Daten sind unveränderbar (Audit-Trail).",
|
||||
"memberNumber": "Nr.",
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"joinedAt": "Beitritt",
|
||||
"usage": "Verbrauch",
|
||||
"strain": "Sorte",
|
||||
"grams": "Gramm",
|
||||
"percent": "Anteil",
|
||||
"batchId": "Chargen-ID",
|
||||
"recalledAt": "Rückruf am",
|
||||
"reason": "Grund",
|
||||
"distributed": "Verteilt",
|
||||
"original": "Original"
|
||||
},
|
||||
"portal": {
|
||||
"title": "Mein Bereich",
|
||||
"login": "Mitglieder-Login",
|
||||
"loginSubtitle": "Melde dich im Mitgliederportal an",
|
||||
"email": "E-Mail-Adresse",
|
||||
"password": "Passwort",
|
||||
"loginButton": "Anmelden",
|
||||
"loggingIn": "Wird angemeldet...",
|
||||
"invalidCredentials": "Ungültige E-Mail-Adresse oder Passwort.",
|
||||
"networkError": "Verbindungsfehler. Bitte versuche es erneut.",
|
||||
"welcome": "Willkommen zurück, {name}!",
|
||||
"dashboard": "Übersicht",
|
||||
"quota": "Mein Kontingent",
|
||||
"history": "Ausgabe-Verlauf",
|
||||
"profile": "Profil",
|
||||
"settings": "Einstellungen",
|
||||
"logout": "Abmelden",
|
||||
"dailyQuota": "Tageskontingent",
|
||||
"monthlyQuota": "Monatskontingent",
|
||||
"remaining": "verbleibend",
|
||||
"used": "verbraucht",
|
||||
"of": "von",
|
||||
"lastDistribution": "Letzte Ausgabe",
|
||||
"noDistributions": "Noch keine Ausgaben in diesem Monat.",
|
||||
"memberSince": "Mitglied seit",
|
||||
"memberNumber": "Mitgliedsnummer",
|
||||
"nextAvailable": "Nächste Verfügbarkeit",
|
||||
"nextAvailableTomorrow": "Morgen ab 00:00 Uhr",
|
||||
"changePassword": "Passwort ändern",
|
||||
"currentPassword": "Aktuelles Passwort",
|
||||
"newPassword": "Neues Passwort",
|
||||
"confirmPassword": "Passwort bestätigen",
|
||||
"passwordChanged": "Passwort erfolgreich geändert.",
|
||||
"passwordMismatch": "Passwörter stimmen nicht überein.",
|
||||
"club": "Mein Verein",
|
||||
"quotaWarning": "Achtung: Du hast bereits {percent}% deines Monatskontingents verbraucht.",
|
||||
"under21Notice": "Für Mitglieder unter 21: Reduziertes Kontingent von 30g/Monat (§19 Abs. 3 KCanG).",
|
||||
"grams": "g",
|
||||
"date": "Datum",
|
||||
"strain": "Sorte",
|
||||
"amount": "Menge",
|
||||
"recordedBy": "Ausgegeben von",
|
||||
"noHistory": "Noch keine Ausgaben vorhanden.",
|
||||
"personalInfo": "Persönliche Daten",
|
||||
"language": "Sprache",
|
||||
"theme": "Design",
|
||||
"themeLight": "Hell",
|
||||
"themeDark": "Dunkel",
|
||||
"themeSystem": "System",
|
||||
"german": "Deutsch",
|
||||
"english": "Englisch",
|
||||
"quickInfo": "Kurzinfo",
|
||||
"todayAvailable": "Heute noch verfügbar",
|
||||
"monthAvailable": "Diesen Monat noch verfügbar",
|
||||
"limitReached": "Limit erreicht",
|
||||
"pagination": "{from}–{to} von {total}",
|
||||
"previous": "Zurück",
|
||||
"next": "Weiter",
|
||||
"allMonths": "Alle Monate",
|
||||
"footerText": "Cannabis-Anbauverein — Sichere Mitgliederverwaltung",
|
||||
"adminLogin": "Zum Admin-Login"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"common": {
|
||||
"appName": "CannaManage",
|
||||
"loading": "Loading...",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"create": "Create",
|
||||
"search": "Search",
|
||||
"filter": "Filter",
|
||||
"export": "Export",
|
||||
"back": "Back",
|
||||
"next": "Next",
|
||||
"confirm": "Confirm",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"noData": "No data available"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
"members": "Members",
|
||||
"stock": "Stock",
|
||||
"distributions": "Distributions",
|
||||
"compliance": "Compliance",
|
||||
"reports": "Reports",
|
||||
"settings": "Settings",
|
||||
"staff": "Staff",
|
||||
"portal": "Member Portal"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Sign In",
|
||||
"logout": "Sign Out",
|
||||
"email": "Email address",
|
||||
"password": "Password",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"resetPassword": "Reset Password",
|
||||
"loginButton": "Sign In",
|
||||
"loggingIn": "Signing in...",
|
||||
"loginSubtitle": "Sign in to your cannabis club",
|
||||
"invalidCredentials": "Invalid email address or password.",
|
||||
"networkError": "Connection error. Please try again.",
|
||||
"sessionExpired": "Your session has expired. Please sign in again.",
|
||||
"emailInvalid": "Please enter a valid email address.",
|
||||
"passwordRequired": "Please enter your password.",
|
||||
"passwordTooShort": "Password must be at least 8 characters.",
|
||||
"footerText": "Secure management for your cannabis cultivation club"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"activeMembers": "Active Members",
|
||||
"distributionsToday": "Distributions Today",
|
||||
"stockLevel": "Stock Level",
|
||||
"monthlyQuota": "Monthly Quota",
|
||||
"quickActions": "Quick Actions",
|
||||
"newDistribution": "New Distribution",
|
||||
"addMember": "Add Member",
|
||||
"recentDistributions": "Recent Distributions",
|
||||
"stockByStrain": "Stock by Strain",
|
||||
"date": "Date",
|
||||
"member": "Member",
|
||||
"strain": "Strain",
|
||||
"amount": "Amount (g)",
|
||||
"staff": "Staff",
|
||||
"grams": "g",
|
||||
"today": "Today",
|
||||
"trend": "+{value}% vs last month",
|
||||
"quotaUsed": "{value}% used",
|
||||
"distributionCount": "{count} distributions, {grams}g"
|
||||
},
|
||||
"members": {
|
||||
"title": "Member Management",
|
||||
"addMember": "Add Member",
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
"status": "Status",
|
||||
"memberSince": "Member Since",
|
||||
"quota": "Quota",
|
||||
"actions": "Actions",
|
||||
"edit": "Edit",
|
||||
"active": "Active",
|
||||
"suspended": "Suspended",
|
||||
"expelled": "Expelled",
|
||||
"back": "Back to List",
|
||||
"save": "Save",
|
||||
"create": "Create Member",
|
||||
"firstName": "First Name",
|
||||
"lastName": "Last Name",
|
||||
"dateOfBirth": "Date of Birth",
|
||||
"phone": "Phone",
|
||||
"memberNumber": "Member Number",
|
||||
"joinedAt": "Joined At",
|
||||
"notes": "Notes",
|
||||
"notesPlaceholder": "Optional notes about the member...",
|
||||
"under21Warning": "Under 21 — reduced quota (30g/month)",
|
||||
"ageError": "Members must be at least 18 years old.",
|
||||
"saved": "Changes saved.",
|
||||
"created": "Member created successfully.",
|
||||
"search": "Search name or email...",
|
||||
"perPage": "Per page",
|
||||
"showing": "{from}–{to} of {total}",
|
||||
"previous": "Previous",
|
||||
"next": "Next",
|
||||
"noResults": "No members found.",
|
||||
"notFound": "Member not found.",
|
||||
"personalInfo": "Personal Information",
|
||||
"membershipInfo": "Membership"
|
||||
},
|
||||
"stock": {
|
||||
"title": "Stock & Batches",
|
||||
"newBatch": "New Batch",
|
||||
"stockOverview": "Stock Overview",
|
||||
"batchId": "Batch ID",
|
||||
"strain": "Strain",
|
||||
"thc": "THC %",
|
||||
"cbd": "CBD %",
|
||||
"status": "Status",
|
||||
"available": "Available",
|
||||
"availableGrams": "Available (g)",
|
||||
"receivedAt": "Received",
|
||||
"actions": "Actions",
|
||||
"statusAvailable": "Available",
|
||||
"statusRecalled": "Recalled",
|
||||
"statusDepleted": "Depleted",
|
||||
"recall": "Recall",
|
||||
"recallConfirm": "Really recall this batch? All open distributions with this batch will be blocked.",
|
||||
"recallTitle": "Recall Batch",
|
||||
"recallSuccess": "Batch recalled.",
|
||||
"totalBatches": "Total Batches",
|
||||
"availableStock": "Available Stock",
|
||||
"recalledBatches": "Recalled Batches",
|
||||
"strainCount": "Strains",
|
||||
"filterAll": "All",
|
||||
"filterAvailable": "Available only",
|
||||
"filterRecalled": "Recalled only",
|
||||
"addBatch": "Add Batch",
|
||||
"strainName": "Strain Name",
|
||||
"amount": "Amount (g)",
|
||||
"supplier": "Supplier / Origin",
|
||||
"harvestDate": "Harvest Date",
|
||||
"notes": "Notes",
|
||||
"notesPlaceholder": "Optional notes about the batch...",
|
||||
"created": "Batch created successfully.",
|
||||
"grams": "g",
|
||||
"confirmRecall": "Confirm Recall",
|
||||
"lowStock": "Low"
|
||||
},
|
||||
"distributions": {
|
||||
"title": "Distributions",
|
||||
"newDistribution": "New Distribution",
|
||||
"todaySummary": "Today: {count} distributions, {grams}g distributed",
|
||||
"dateTime": "Date/Time",
|
||||
"member": "Member",
|
||||
"strain": "Strain",
|
||||
"amount": "Amount (g)",
|
||||
"staff": "Staff",
|
||||
"status": "Status",
|
||||
"completed": "Completed",
|
||||
"locked": "Locked (immutable)",
|
||||
"filterToday": "Today",
|
||||
"filterWeek": "This Week",
|
||||
"filterMonth": "This Month",
|
||||
"searchMember": "Search member...",
|
||||
"step1": "Select Member",
|
||||
"step2": "Check Quota",
|
||||
"step3": "Strain & Amount",
|
||||
"step4": "Confirmation",
|
||||
"selectMember": "Search member (name or number)...",
|
||||
"memberBlocked": "Member is blocked — distribution not possible.",
|
||||
"under21Info": "Reduced quota: 30g/month (under 21)",
|
||||
"dailyRemaining": "Daily remaining",
|
||||
"monthlyRemaining": "Monthly remaining",
|
||||
"selectBatch": "Select batch",
|
||||
"available": "available",
|
||||
"amountLabel": "Amount in grams",
|
||||
"exceedsDaily": "Exceeds daily limit ({limit}g).",
|
||||
"exceedsMonthly": "Exceeds monthly limit ({limit}g).",
|
||||
"exceedsBatch": "Insufficient stock in this batch.",
|
||||
"confirm": "Confirm Distribution",
|
||||
"summary": "Summary",
|
||||
"success": "Distribution recorded successfully.",
|
||||
"grams": "g",
|
||||
"date": "Date",
|
||||
"monthlyQuota": "Monthly Quota",
|
||||
"remaining": "Remaining"
|
||||
},
|
||||
"reports": {
|
||||
"title": "Reports",
|
||||
"monthly": "Monthly Report",
|
||||
"monthlyDesc": "Overview of all distributions in the selected month, including member quotas and stock changes.",
|
||||
"memberList": "Member List",
|
||||
"memberListDesc": "Complete member list with status, quota utilization and contact details.",
|
||||
"recall": "Recall Report",
|
||||
"recallDesc": "All batches with recall status and affected distributions for regulatory reporting.",
|
||||
"downloadPdf": "Download as PDF",
|
||||
"downloadCsv": "Download as CSV",
|
||||
"preview": "Show Preview",
|
||||
"generating": "Generating report...",
|
||||
"downloaded": "{name} downloaded.",
|
||||
"selectMonth": "Select month",
|
||||
"selectStatus": "Filter by status",
|
||||
"allStatuses": "All",
|
||||
"activeOnly": "Active",
|
||||
"suspendedOnly": "Suspended",
|
||||
"dateFrom": "From",
|
||||
"dateTo": "To",
|
||||
"previewTitle": "Report Preview",
|
||||
"totalDistributions": "Total Distributions",
|
||||
"totalGrams": "Total Grams",
|
||||
"uniqueMembers": "Unique Members",
|
||||
"averagePerMember": "Avg per Member",
|
||||
"topStrains": "Top Strains",
|
||||
"affectedDistributions": "Affected Distributions",
|
||||
"affectedMembers": "Affected Members",
|
||||
"recalledBatches": "Recalled Batches",
|
||||
"close": "Close",
|
||||
"complianceNote": "This report is suitable for submission to the responsible authority.",
|
||||
"complianceBadge": "§19 KCanG compliant",
|
||||
"auditTrail": "All reports are generated with timestamps. The underlying distribution data is immutable (audit trail).",
|
||||
"memberNumber": "No.",
|
||||
"name": "Name",
|
||||
"status": "Status",
|
||||
"joinedAt": "Joined",
|
||||
"usage": "Usage",
|
||||
"strain": "Strain",
|
||||
"grams": "Grams",
|
||||
"percent": "Share",
|
||||
"batchId": "Batch ID",
|
||||
"recalledAt": "Recalled on",
|
||||
"reason": "Reason",
|
||||
"distributed": "Distributed",
|
||||
"original": "Original"
|
||||
},
|
||||
"portal": {
|
||||
"title": "My Area",
|
||||
"login": "Member Login",
|
||||
"loginSubtitle": "Sign in to the member portal",
|
||||
"email": "Email address",
|
||||
"password": "Password",
|
||||
"loginButton": "Sign In",
|
||||
"loggingIn": "Signing in...",
|
||||
"invalidCredentials": "Invalid email address or password.",
|
||||
"networkError": "Connection error. Please try again.",
|
||||
"welcome": "Welcome back, {name}!",
|
||||
"dashboard": "Overview",
|
||||
"quota": "My Quota",
|
||||
"history": "Distribution History",
|
||||
"profile": "Profile",
|
||||
"settings": "Settings",
|
||||
"logout": "Sign Out",
|
||||
"dailyQuota": "Daily Quota",
|
||||
"monthlyQuota": "Monthly Quota",
|
||||
"remaining": "remaining",
|
||||
"used": "used",
|
||||
"of": "of",
|
||||
"lastDistribution": "Last Distribution",
|
||||
"noDistributions": "No distributions this month yet.",
|
||||
"memberSince": "Member since",
|
||||
"memberNumber": "Member number",
|
||||
"nextAvailable": "Next available",
|
||||
"nextAvailableTomorrow": "Tomorrow at 00:00",
|
||||
"changePassword": "Change Password",
|
||||
"currentPassword": "Current Password",
|
||||
"newPassword": "New Password",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"passwordChanged": "Password changed successfully.",
|
||||
"passwordMismatch": "Passwords do not match.",
|
||||
"club": "My Club",
|
||||
"quotaWarning": "Warning: You have already used {percent}% of your monthly quota.",
|
||||
"under21Notice": "For members under 21: Reduced quota of 30g/month (§19 Abs. 3 KCanG).",
|
||||
"grams": "g",
|
||||
"date": "Date",
|
||||
"strain": "Strain",
|
||||
"amount": "Amount",
|
||||
"recordedBy": "Recorded by",
|
||||
"noHistory": "No distributions recorded yet.",
|
||||
"personalInfo": "Personal Information",
|
||||
"language": "Language",
|
||||
"theme": "Theme",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"themeSystem": "System",
|
||||
"german": "German",
|
||||
"english": "English",
|
||||
"quickInfo": "Quick Info",
|
||||
"todayAvailable": "Available today",
|
||||
"monthAvailable": "Available this month",
|
||||
"limitReached": "Limit reached",
|
||||
"pagination": "{from}–{to} of {total}",
|
||||
"previous": "Previous",
|
||||
"next": "Next",
|
||||
"allMonths": "All months",
|
||||
"footerText": "Cannabis cultivation club — Secure member management",
|
||||
"adminLogin": "Go to Admin Login"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user