fix: QA audit — lint cleanup, i18n fixes, module visibility, sidebar UX
- Fix 97 lint errors → 0 (unused imports, params, variables across 40+ files) - Fix i18n key format: colon → dot notation for next-intl compatibility - Add missing i18n keys (routes.application, routes.home, confirm) - Fix module visibility: sidebar now respects per-account DB features - Fix inject function: use dot-notation keys, add collapsed:true defaults - Fix ConfirmDialog: use useTranslations instead of hardcoded German defaults - Fix events page: replace placeholder 'Beschreibung' with proper description - Fix Dockerfile: add NEXT_PUBLIC_CI ARG for Docker builds - Collapse secondary sidebar sections by default for cleaner UX
This commit is contained in:
@@ -13,6 +13,7 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
|||||||
|
|
||||||
# NEXT_PUBLIC_* vars are baked into the Next.js build at compile time.
|
# NEXT_PUBLIC_* vars are baked into the Next.js build at compile time.
|
||||||
# Pass them as build args so the same Dockerfile works for any environment.
|
# Pass them as build args so the same Dockerfile works for any environment.
|
||||||
|
ARG NEXT_PUBLIC_CI=false
|
||||||
ARG NEXT_PUBLIC_SITE_URL=https://myeasycms.de
|
ARG NEXT_PUBLIC_SITE_URL=https://myeasycms.de
|
||||||
ARG NEXT_PUBLIC_SUPABASE_URL=http://localhost:8000
|
ARG NEXT_PUBLIC_SUPABASE_URL=http://localhost:8000
|
||||||
ARG NEXT_PUBLIC_SUPABASE_PUBLIC_KEY
|
ARG NEXT_PUBLIC_SUPABASE_PUBLIC_KEY
|
||||||
@@ -20,6 +21,7 @@ ARG NEXT_PUBLIC_DEFAULT_LOCALE=de
|
|||||||
ARG NEXT_PUBLIC_ENABLE_FISCHEREI=true
|
ARG NEXT_PUBLIC_ENABLE_FISCHEREI=true
|
||||||
ARG NEXT_PUBLIC_ENABLE_MEETING_PROTOCOLS=true
|
ARG NEXT_PUBLIC_ENABLE_MEETING_PROTOCOLS=true
|
||||||
ARG NEXT_PUBLIC_ENABLE_VERBANDSVERWALTUNG=true
|
ARG NEXT_PUBLIC_ENABLE_VERBANDSVERWALTUNG=true
|
||||||
|
ENV NEXT_PUBLIC_CI=${NEXT_PUBLIC_CI}
|
||||||
ENV NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL}
|
ENV NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL}
|
||||||
ENV NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}
|
ENV NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}
|
||||||
ENV NEXT_PUBLIC_SUPABASE_PUBLIC_KEY=${NEXT_PUBLIC_SUPABASE_PUBLIC_KEY}
|
ENV NEXT_PUBLIC_SUPABASE_PUBLIC_KEY=${NEXT_PUBLIC_SUPABASE_PUBLIC_KEY}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* E2E Test: Course Enrollment
|
* E2E Test: Course Enrollment
|
||||||
*/
|
*/
|
||||||
import { test, expect } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
test.describe('Course Management', () => {
|
test.describe('Course Management', () => {
|
||||||
test('create course, enroll participant, check capacity, waitlist', async ({
|
test('create course, enroll participant, check capacity, waitlist', async ({
|
||||||
page,
|
page: _page,
|
||||||
}) => {
|
}) => {
|
||||||
// Create course with capacity 2
|
// Create course with capacity 2
|
||||||
// Enroll participant 1 → status: enrolled
|
// Enroll participant 1 → status: enrolled
|
||||||
@@ -13,13 +13,13 @@ test.describe('Course Management', () => {
|
|||||||
// Enroll participant 3 → status: waitlisted (capacity full)
|
// Enroll participant 3 → status: waitlisted (capacity full)
|
||||||
});
|
});
|
||||||
|
|
||||||
test('course calendar view shows sessions', async ({ page }) => {
|
test('course calendar view shows sessions', async ({ page: _page }) => {
|
||||||
// Create course with sessions
|
// Create course with sessions
|
||||||
// Navigate to calendar
|
// Navigate to calendar
|
||||||
// Verify sessions visible
|
// Verify sessions visible
|
||||||
});
|
});
|
||||||
|
|
||||||
test('attendance tracking', async ({ page }) => {
|
test('attendance tracking', async ({ page: _page }) => {
|
||||||
// Create course + session + participants
|
// Create course + session + participants
|
||||||
// Mark attendance
|
// Mark attendance
|
||||||
// Verify attendance persists
|
// Verify attendance persists
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
test.describe('Member Management', () => {
|
test.describe('Member Management', () => {
|
||||||
test('create member, edit, search, filter by status', async ({ page }) => {
|
test('create member, edit, search, filter by status', async ({ page: _page }) => {
|
||||||
await page.goto('/auth/sign-in');
|
await page.goto('/auth/sign-in');
|
||||||
await page.fill('input[name="email"]', 'test@example.com');
|
await page.fill('input[name="email"]', 'test@example.com');
|
||||||
await page.fill('input[name="password"]', 'testpassword123');
|
await page.fill('input[name="password"]', 'testpassword123');
|
||||||
@@ -16,14 +16,14 @@ test.describe('Member Management', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('application workflow: submit → review → approve → member created', async ({
|
test('application workflow: submit → review → approve → member created', async ({
|
||||||
page,
|
page: _page,
|
||||||
}) => {
|
}) => {
|
||||||
// Submit application
|
// Submit application
|
||||||
// Review application
|
// Review application
|
||||||
// Approve → verify member auto-created
|
// Approve → verify member auto-created
|
||||||
});
|
});
|
||||||
|
|
||||||
test('SEPA mandate management', async ({ page }) => {
|
test('SEPA mandate management', async ({ page: _page }) => {
|
||||||
// Create member with IBAN
|
// Create member with IBAN
|
||||||
// Verify IBAN validation
|
// Verify IBAN validation
|
||||||
// Create SEPA batch from dues
|
// Create SEPA batch from dues
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { test, expect } from '@playwright/test';
|
|||||||
|
|
||||||
test.describe('Module Builder', () => {
|
test.describe('Module Builder', () => {
|
||||||
test('create module, add fields, insert record, query, update, soft-delete', async ({
|
test('create module, add fields, insert record, query, update, soft-delete', async ({
|
||||||
page,
|
page: _page,
|
||||||
}) => {
|
}) => {
|
||||||
// Login
|
// Login
|
||||||
await page.goto('/auth/sign-in');
|
await page.goto('/auth/sign-in');
|
||||||
@@ -24,7 +24,7 @@ test.describe('Module Builder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Cross-tenant isolation', () => {
|
test.describe('Cross-tenant isolation', () => {
|
||||||
test('tenant A cannot see tenant B data', async ({ page }) => {
|
test('tenant A cannot see tenant B data', async ({ page: _page }) => {
|
||||||
// Login as tenant A user
|
// Login as tenant A user
|
||||||
// Verify can see own modules
|
// Verify can see own modules
|
||||||
// Verify cannot access tenant B module URL
|
// Verify cannot access tenant B module URL
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* E2E Test: Newsletter
|
* E2E Test: Newsletter
|
||||||
*/
|
*/
|
||||||
import { test, expect } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
test.describe('Newsletter', () => {
|
test.describe('Newsletter', () => {
|
||||||
test('create campaign, select recipients from members, preview, send', async ({
|
test('create campaign, select recipients from members, preview, send', async ({
|
||||||
page,
|
page: _page,
|
||||||
}) => {
|
}) => {
|
||||||
// Create newsletter
|
// Create newsletter
|
||||||
// Add recipients from member filter (status=active, hasEmail=true)
|
// Add recipients from member filter (status=active, hasEmail=true)
|
||||||
@@ -14,7 +14,7 @@ test.describe('Newsletter', () => {
|
|||||||
// Verify sent_count
|
// Verify sent_count
|
||||||
});
|
});
|
||||||
|
|
||||||
test('template variable substitution works', async ({ page }) => {
|
test('template variable substitution works', async ({ page: _page }) => {
|
||||||
// Create template with {{first_name}} {{member_number}}
|
// Create template with {{first_name}} {{member_number}}
|
||||||
// Create newsletter from template
|
// Create newsletter from template
|
||||||
// Preview — verify variables replaced
|
// Preview — verify variables replaced
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* E2E Test: SEPA Batch Processing
|
* E2E Test: SEPA Batch Processing
|
||||||
*/
|
*/
|
||||||
import { test, expect } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
test.describe('SEPA / Finance', () => {
|
test.describe('SEPA / Finance', () => {
|
||||||
test('create SEPA direct debit batch, add items, generate XML', async ({
|
test('create SEPA direct debit batch, add items, generate XML', async ({
|
||||||
page,
|
page: _page,
|
||||||
}) => {
|
}) => {
|
||||||
// Create batch
|
// Create batch
|
||||||
// Add items with valid IBANs
|
// Add items with valid IBANs
|
||||||
@@ -14,12 +14,12 @@ test.describe('SEPA / Finance', () => {
|
|||||||
// Verify amounts sum correctly
|
// Verify amounts sum correctly
|
||||||
});
|
});
|
||||||
|
|
||||||
test('IBAN validation rejects invalid IBANs', async ({ page }) => {
|
test('IBAN validation rejects invalid IBANs', async ({ page: _page }) => {
|
||||||
// Try to add item with invalid IBAN
|
// Try to add item with invalid IBAN
|
||||||
// Verify rejection
|
// Verify rejection
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invoice creation with line items', async ({ page }) => {
|
test('invoice creation with line items', async ({ page: _page }) => {
|
||||||
// Create invoice
|
// Create invoice
|
||||||
// Add 3 line items
|
// Add 3 line items
|
||||||
// Verify subtotal, tax, total calculations
|
// Verify subtotal, tax, total calculations
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function NewsletterSubscribePage({ params }: Props) {
|
export default async function NewsletterSubscribePage({ params }: Props) {
|
||||||
const { slug } = await params;
|
const { slug: _slug } = await params;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-muted/30 flex min-h-screen items-center justify-center p-6">
|
<div className="bg-muted/30 flex min-h-screen items-center justify-center p-6">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useState } from 'react';
|
|||||||
import type { Provider, UserIdentity } from '@supabase/supabase-js';
|
import type { Provider, UserIdentity } from '@supabase/supabase-js';
|
||||||
import { createClient } from '@supabase/supabase-js';
|
import { createClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
import { Link2, Link2Off, Loader2 } from 'lucide-react';
|
import { Link2Off, Loader2 } from 'lucide-react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
import { Plus, Users } from 'lucide-react';
|
import { Plus, Users } from 'lucide-react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
Plus,
|
Plus,
|
||||||
Users,
|
Users,
|
||||||
Calendar,
|
Calendar,
|
||||||
Euro,
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,9 @@ async function generateMemberCards(
|
|||||||
Text,
|
Text,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
renderToBuffer,
|
renderToBuffer,
|
||||||
Svg,
|
Svg: _Svg,
|
||||||
Rect,
|
Rect: _Rect,
|
||||||
Circle,
|
Circle: _Circle,
|
||||||
} = await import('@react-pdf/renderer');
|
} = await import('@react-pdf/renderer');
|
||||||
|
|
||||||
// — Brand colors (configurable later via account settings) —
|
// — Brand colors (configurable later via account settings) —
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
import { FileText, Plus } from 'lucide-react';
|
import { FileText, Plus } from 'lucide-react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
|
|||||||
@@ -96,36 +96,37 @@ function injectAccountFeatureRoutes(
|
|||||||
|
|
||||||
if (features.fischerei) {
|
if (features.fischerei) {
|
||||||
featureGroups.push({
|
featureGroups.push({
|
||||||
label: 'common:routes.fisheriesManagement',
|
label: 'common.routes.fisheriesManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesOverview',
|
label: 'common.routes.fisheriesOverview',
|
||||||
path: `/home/${account}/fischerei`,
|
path: `/home/${account}/fischerei`,
|
||||||
Icon: <Fish className={iconClasses} />,
|
Icon: <Fish className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesWaters',
|
label: 'common.routes.fisheriesWaters',
|
||||||
path: `/home/${account}/fischerei/waters`,
|
path: `/home/${account}/fischerei/waters`,
|
||||||
Icon: <Waves className={iconClasses} />,
|
Icon: <Waves className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesLeases',
|
label: 'common.routes.fisheriesLeases',
|
||||||
path: `/home/${account}/fischerei/leases`,
|
path: `/home/${account}/fischerei/leases`,
|
||||||
Icon: <Anchor className={iconClasses} />,
|
Icon: <Anchor className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesCatchBooks',
|
label: 'common.routes.fisheriesCatchBooks',
|
||||||
path: `/home/${account}/fischerei/catch-books`,
|
path: `/home/${account}/fischerei/catch-books`,
|
||||||
Icon: <BookOpen className={iconClasses} />,
|
Icon: <BookOpen className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesPermits',
|
label: 'common.routes.fisheriesPermits',
|
||||||
path: `/home/${account}/fischerei/permits`,
|
path: `/home/${account}/fischerei/permits`,
|
||||||
Icon: <ShieldCheck className={iconClasses} />,
|
Icon: <ShieldCheck className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.fisheriesCompetitions',
|
label: 'common.routes.fisheriesCompetitions',
|
||||||
path: `/home/${account}/fischerei/competitions`,
|
path: `/home/${account}/fischerei/competitions`,
|
||||||
Icon: <Trophy className={iconClasses} />,
|
Icon: <Trophy className={iconClasses} />,
|
||||||
},
|
},
|
||||||
@@ -135,21 +136,22 @@ function injectAccountFeatureRoutes(
|
|||||||
|
|
||||||
if (features.meetings) {
|
if (features.meetings) {
|
||||||
featureGroups.push({
|
featureGroups.push({
|
||||||
label: 'common:routes.meetingProtocols',
|
label: 'common.routes.meetingProtocols',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.meetingsOverview',
|
label: 'common.routes.meetingsOverview',
|
||||||
path: `/home/${account}/meetings`,
|
path: `/home/${account}/meetings`,
|
||||||
Icon: <BookMarked className={iconClasses} />,
|
Icon: <BookMarked className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.meetingsProtocols',
|
label: 'common.routes.meetingsProtocols',
|
||||||
path: `/home/${account}/meetings/protocols`,
|
path: `/home/${account}/meetings/protocols`,
|
||||||
Icon: <ScrollText className={iconClasses} />,
|
Icon: <ScrollText className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.meetingsTasks',
|
label: 'common.routes.meetingsTasks',
|
||||||
path: `/home/${account}/meetings/tasks`,
|
path: `/home/${account}/meetings/tasks`,
|
||||||
Icon: <ListChecks className={iconClasses} />,
|
Icon: <ListChecks className={iconClasses} />,
|
||||||
},
|
},
|
||||||
@@ -159,36 +161,37 @@ function injectAccountFeatureRoutes(
|
|||||||
|
|
||||||
if (features.verband) {
|
if (features.verband) {
|
||||||
featureGroups.push({
|
featureGroups.push({
|
||||||
label: 'common:routes.associationManagement',
|
label: 'common.routes.associationManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationOverview',
|
label: 'common.routes.associationOverview',
|
||||||
path: `/home/${account}/verband`,
|
path: `/home/${account}/verband`,
|
||||||
Icon: <Building2 className={iconClasses} />,
|
Icon: <Building2 className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationHierarchy',
|
label: 'common.routes.associationHierarchy',
|
||||||
path: `/home/${account}/verband/hierarchy`,
|
path: `/home/${account}/verband/hierarchy`,
|
||||||
Icon: <Network className={iconClasses} />,
|
Icon: <Network className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationMemberSearch',
|
label: 'common.routes.associationMemberSearch',
|
||||||
path: `/home/${account}/verband/members`,
|
path: `/home/${account}/verband/members`,
|
||||||
Icon: <SearchCheck className={iconClasses} />,
|
Icon: <SearchCheck className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationEvents',
|
label: 'common.routes.associationEvents',
|
||||||
path: `/home/${account}/verband/events`,
|
path: `/home/${account}/verband/events`,
|
||||||
Icon: <Share2 className={iconClasses} />,
|
Icon: <Share2 className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationReporting',
|
label: 'common.routes.associationReporting',
|
||||||
path: `/home/${account}/verband/reporting`,
|
path: `/home/${account}/verband/reporting`,
|
||||||
Icon: <PieChart className={iconClasses} />,
|
Icon: <PieChart className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.associationTemplates',
|
label: 'common.routes.associationTemplates',
|
||||||
path: `/home/${account}/verband/templates`,
|
path: `/home/${account}/verband/templates`,
|
||||||
Icon: <LayoutTemplate className={iconClasses} />,
|
Icon: <LayoutTemplate className={iconClasses} />,
|
||||||
},
|
},
|
||||||
@@ -222,7 +225,7 @@ async function SidebarLayout({
|
|||||||
redirect('/');
|
redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseConfig = getTeamAccountSidebarConfig(account);
|
const baseConfig = getTeamAccountSidebarConfig(account, features);
|
||||||
const config = injectAccountFeatureRoutes(baseConfig, account, features);
|
const config = injectAccountFeatureRoutes(baseConfig, account, features);
|
||||||
|
|
||||||
const accounts = data.accounts.map(({ name, slug, picture_url }) => ({
|
const accounts = data.accounts.map(({ name, slug, picture_url }) => ({
|
||||||
@@ -275,7 +278,7 @@ async function HeaderLayout({
|
|||||||
getAccountFeatures(account),
|
getAccountFeatures(account),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const baseConfig = getTeamAccountSidebarConfig(account);
|
const baseConfig = getTeamAccountSidebarConfig(account, features);
|
||||||
const config = injectAccountFeatureRoutes(baseConfig, account, features);
|
const config = injectAccountFeatureRoutes(baseConfig, account, features);
|
||||||
|
|
||||||
const accounts = data.accounts.map(({ name, slug, picture_url }) => ({
|
const accounts = data.accounts.map(({ name, slug, picture_url }) => ({
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ export function InvitationsView({
|
|||||||
invitations,
|
invitations,
|
||||||
members,
|
members,
|
||||||
accountId,
|
accountId,
|
||||||
account,
|
|
||||||
}: InvitationsViewProps) {
|
}: InvitationsViewProps) {
|
||||||
const t = useTranslations('members');
|
const t = useTranslations('members');
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Link2, List } from 'lucide-react';
|
import { List } from 'lucide-react';
|
||||||
|
|
||||||
import { createModuleBuilderApi } from '@kit/module-builder/api';
|
import { createModuleBuilderApi } from '@kit/module-builder/api';
|
||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
import { FileText, Plus } from 'lucide-react';
|
import { FileText, Plus } from 'lucide-react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { createSiteBuilderApi } from '@kit/site-builder/api';
|
|||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
import { Badge } from '@kit/ui/badge';
|
import { Badge } from '@kit/ui/badge';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
import { Card, CardContent } from '@kit/ui/card';
|
||||||
import { cn } from '@kit/ui/utils';
|
import { cn } from '@kit/ui/utils';
|
||||||
|
|
||||||
import { AccountNotFound } from '~/components/account-not-found';
|
import { AccountNotFound } from '~/components/account-not-found';
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
import { getTranslations } from 'next-intl/server';
|
import { getTranslations } from 'next-intl/server';
|
||||||
|
|
||||||
@@ -15,7 +13,6 @@ import { createSiteBuilderApi } from '@kit/site-builder/api';
|
|||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
import { Badge } from '@kit/ui/badge';
|
import { Badge } from '@kit/ui/badge';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
import { Card, CardContent } from '@kit/ui/card';
|
|
||||||
|
|
||||||
import { AccountNotFound } from '~/components/account-not-found';
|
import { AccountNotFound } from '~/components/account-not-found';
|
||||||
import { CmsPageShell } from '~/components/cms-page-shell';
|
import { CmsPageShell } from '~/components/cms-page-shell';
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ async function getSupabaseHealthCheck() {
|
|||||||
try {
|
try {
|
||||||
const client = getSupabaseServerAdminClient();
|
const client = getSupabaseServerAdminClient();
|
||||||
|
|
||||||
const { data, error } = await client
|
const { data: _data, error } = await client
|
||||||
.from('config')
|
.from('config')
|
||||||
.select('billing_provider')
|
.select('billing_provider')
|
||||||
.limit(1)
|
.limit(1)
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ import { Noto_Serif } from 'next/font/google';
|
|||||||
const notoSerif = Noto_Serif({ subsets: ['latin'], variable: '--font-serif' });
|
const notoSerif = Noto_Serif({ subsets: ['latin'], variable: '--font-serif' });
|
||||||
|
|
||||||
export default function RootLayout({ children }: React.PropsWithChildren) {
|
export default function RootLayout({ children }: React.PropsWithChildren) {
|
||||||
return children;
|
return <div className={notoSerif.variable}>{children}</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogAction,
|
AlertDialogAction,
|
||||||
@@ -26,11 +28,15 @@ export function ConfirmDialog({
|
|||||||
trigger,
|
trigger,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
confirmLabel = 'Bestätigen',
|
confirmLabel,
|
||||||
cancelLabel = 'Abbrechen',
|
cancelLabel,
|
||||||
variant = 'default',
|
variant = 'default',
|
||||||
onConfirm,
|
onConfirm,
|
||||||
}: ConfirmDialogProps) {
|
}: ConfirmDialogProps) {
|
||||||
|
const t = useTranslations('common');
|
||||||
|
const resolvedConfirmLabel = confirmLabel ?? t('confirm');
|
||||||
|
const resolvedCancelLabel = cancelLabel ?? t('cancel');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger
|
<AlertDialogTrigger
|
||||||
@@ -42,7 +48,7 @@ export function ConfirmDialog({
|
|||||||
<AlertDialogDescription>{description}</AlertDialogDescription>
|
<AlertDialogDescription>{description}</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>{cancelLabel}</AlertDialogCancel>
|
<AlertDialogCancel>{resolvedCancelLabel}</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
className={
|
className={
|
||||||
@@ -51,7 +57,7 @@ export function ConfirmDialog({
|
|||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{confirmLabel}
|
{resolvedConfirmLabel}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
@@ -40,6 +40,24 @@ import {
|
|||||||
PanelTop,
|
PanelTop,
|
||||||
Newspaper,
|
Newspaper,
|
||||||
Palette,
|
Palette,
|
||||||
|
// Fisheries
|
||||||
|
Fish,
|
||||||
|
Waves,
|
||||||
|
Anchor,
|
||||||
|
BookOpen,
|
||||||
|
ShieldCheck,
|
||||||
|
Trophy,
|
||||||
|
// Meetings
|
||||||
|
BookMarked,
|
||||||
|
ListChecks,
|
||||||
|
ScrollText,
|
||||||
|
// Association (Verband)
|
||||||
|
Building2,
|
||||||
|
Network,
|
||||||
|
SearchCheck,
|
||||||
|
Share2,
|
||||||
|
PieChart,
|
||||||
|
LayoutTemplate,
|
||||||
// Modules
|
// Modules
|
||||||
Database,
|
Database,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
@@ -51,7 +69,7 @@ import pathsConfig from '~/config/paths.config';
|
|||||||
|
|
||||||
const iconClasses = 'w-4';
|
const iconClasses = 'w-4';
|
||||||
|
|
||||||
const getRoutes = (account: string) => {
|
const getRoutes = (account: string, accountFeatures?: Record<string, boolean>) => {
|
||||||
const routes: Array<
|
const routes: Array<
|
||||||
| {
|
| {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -71,10 +89,10 @@ const getRoutes = (account: string) => {
|
|||||||
> = [
|
> = [
|
||||||
// ── Dashboard ──
|
// ── Dashboard ──
|
||||||
{
|
{
|
||||||
label: 'common:routes.dashboard',
|
label: 'common.routes.dashboard',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.dashboard',
|
label: 'common.routes.dashboard',
|
||||||
path: pathsConfig.app.accountHome.replace('[account]', account),
|
path: pathsConfig.app.accountHome.replace('[account]', account),
|
||||||
Icon: <LayoutDashboard className={iconClasses} />,
|
Icon: <LayoutDashboard className={iconClasses} />,
|
||||||
highlightMatch: `${pathsConfig.app.home}$`,
|
highlightMatch: `${pathsConfig.app.home}$`,
|
||||||
@@ -94,12 +112,12 @@ const getRoutes = (account: string) => {
|
|||||||
if (featureFlagsConfig.enableMemberManagement) {
|
if (featureFlagsConfig.enableMemberManagement) {
|
||||||
peopleChildren.push(
|
peopleChildren.push(
|
||||||
{
|
{
|
||||||
label: 'common:routes.clubMembers',
|
label: 'common.routes.clubMembers',
|
||||||
path: createPath(pathsConfig.app.accountCmsMembers, account),
|
path: createPath(pathsConfig.app.accountCmsMembers, account),
|
||||||
Icon: <UserCheck className={iconClasses} />,
|
Icon: <UserCheck className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.memberApplications',
|
label: 'common.routes.memberApplications',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCmsMembers + '/applications',
|
pathsConfig.app.accountCmsMembers + '/applications',
|
||||||
account,
|
account,
|
||||||
@@ -108,7 +126,7 @@ const getRoutes = (account: string) => {
|
|||||||
},
|
},
|
||||||
// NOTE: memberPortal page does not exist yet — nav entry commented out until built
|
// NOTE: memberPortal page does not exist yet — nav entry commented out until built
|
||||||
// {
|
// {
|
||||||
// label: 'common:routes.memberPortal',
|
// label: 'common.routes.memberPortal',
|
||||||
// path: createPath(
|
// path: createPath(
|
||||||
// pathsConfig.app.accountCmsMembers + '/portal',
|
// pathsConfig.app.accountCmsMembers + '/portal',
|
||||||
// account,
|
// account,
|
||||||
@@ -116,7 +134,7 @@ const getRoutes = (account: string) => {
|
|||||||
// Icon: <KeyRound className={iconClasses} />,
|
// Icon: <KeyRound className={iconClasses} />,
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
label: 'common:routes.memberCards',
|
label: 'common.routes.memberCards',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCmsMembers + '/cards',
|
pathsConfig.app.accountCmsMembers + '/cards',
|
||||||
account,
|
account,
|
||||||
@@ -124,7 +142,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <IdCard className={iconClasses} />,
|
Icon: <IdCard className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.memberDues',
|
label: 'common.routes.memberDues',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCmsMembers + '/dues',
|
pathsConfig.app.accountCmsMembers + '/dues',
|
||||||
account,
|
account,
|
||||||
@@ -136,13 +154,13 @@ const getRoutes = (account: string) => {
|
|||||||
|
|
||||||
// Admin users who can log in — always visible
|
// Admin users who can log in — always visible
|
||||||
peopleChildren.push({
|
peopleChildren.push({
|
||||||
label: 'common:routes.accessAndRoles',
|
label: 'common.routes.accessAndRoles',
|
||||||
path: createPath(pathsConfig.app.accountMembers, account),
|
path: createPath(pathsConfig.app.accountMembers, account),
|
||||||
Icon: <UserCog className={iconClasses} />,
|
Icon: <UserCog className={iconClasses} />,
|
||||||
});
|
});
|
||||||
|
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.people',
|
label: 'common.routes.people',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
children: peopleChildren,
|
children: peopleChildren,
|
||||||
});
|
});
|
||||||
@@ -151,16 +169,16 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Courses ──
|
// ── Courses ──
|
||||||
if (featureFlagsConfig.enableCourseManagement) {
|
if (featureFlagsConfig.enableCourseManagement) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.courseManagement',
|
label: 'common.routes.courseManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.courseList',
|
label: 'common.routes.courseList',
|
||||||
path: createPath(pathsConfig.app.accountCourses, account),
|
path: createPath(pathsConfig.app.accountCourses, account),
|
||||||
Icon: <GraduationCap className={iconClasses} />,
|
Icon: <GraduationCap className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.courseCalendar',
|
label: 'common.routes.courseCalendar',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCourses + '/calendar',
|
pathsConfig.app.accountCourses + '/calendar',
|
||||||
account,
|
account,
|
||||||
@@ -168,7 +186,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <CalendarDays className={iconClasses} />,
|
Icon: <CalendarDays className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.courseInstructors',
|
label: 'common.routes.courseInstructors',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCourses + '/instructors',
|
pathsConfig.app.accountCourses + '/instructors',
|
||||||
account,
|
account,
|
||||||
@@ -176,7 +194,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <UserRound className={iconClasses} />,
|
Icon: <UserRound className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.courseLocations',
|
label: 'common.routes.courseLocations',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountCourses + '/locations',
|
pathsConfig.app.accountCourses + '/locations',
|
||||||
account,
|
account,
|
||||||
@@ -189,21 +207,21 @@ const getRoutes = (account: string) => {
|
|||||||
|
|
||||||
// ── Events ──
|
// ── Events ──
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.eventManagement',
|
label: 'common.routes.eventManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.eventList',
|
label: 'common.routes.eventList',
|
||||||
path: createPath('/home/[account]/events', account),
|
path: createPath('/home/[account]/events', account),
|
||||||
Icon: <CalendarHeart className={iconClasses} />,
|
Icon: <CalendarHeart className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.eventRegistrations',
|
label: 'common.routes.eventRegistrations',
|
||||||
path: createPath('/home/[account]/events/registrations', account),
|
path: createPath('/home/[account]/events/registrations', account),
|
||||||
Icon: <Ticket className={iconClasses} />,
|
Icon: <Ticket className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.holidayPasses',
|
label: 'common.routes.holidayPasses',
|
||||||
path: createPath('/home/[account]/events/holiday-passes', account),
|
path: createPath('/home/[account]/events/holiday-passes', account),
|
||||||
Icon: <PartyPopper className={iconClasses} />,
|
Icon: <PartyPopper className={iconClasses} />,
|
||||||
},
|
},
|
||||||
@@ -213,16 +231,17 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Bookings ──
|
// ── Bookings ──
|
||||||
if (featureFlagsConfig.enableBookingManagement) {
|
if (featureFlagsConfig.enableBookingManagement) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.bookingManagement',
|
label: 'common.routes.bookingManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.bookingList',
|
label: 'common.routes.bookingList',
|
||||||
path: createPath(pathsConfig.app.accountBookings, account),
|
path: createPath(pathsConfig.app.accountBookings, account),
|
||||||
Icon: <Hotel className={iconClasses} />,
|
Icon: <Hotel className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.bookingCalendar',
|
label: 'common.routes.bookingCalendar',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountBookings + '/calendar',
|
pathsConfig.app.accountBookings + '/calendar',
|
||||||
account,
|
account,
|
||||||
@@ -230,12 +249,12 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <CalendarRange className={iconClasses} />,
|
Icon: <CalendarRange className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.bookingRooms',
|
label: 'common.routes.bookingRooms',
|
||||||
path: createPath(pathsConfig.app.accountBookings + '/rooms', account),
|
path: createPath(pathsConfig.app.accountBookings + '/rooms', account),
|
||||||
Icon: <BedDouble className={iconClasses} />,
|
Icon: <BedDouble className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.bookingGuests',
|
label: 'common.routes.bookingGuests',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountBookings + '/guests',
|
pathsConfig.app.accountBookings + '/guests',
|
||||||
account,
|
account,
|
||||||
@@ -249,16 +268,17 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Finance ──
|
// ── Finance ──
|
||||||
if (featureFlagsConfig.enableSepaPayments) {
|
if (featureFlagsConfig.enableSepaPayments) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.financeManagement',
|
label: 'common.routes.financeManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.financeOverview',
|
label: 'common.routes.financeOverview',
|
||||||
path: createPath(pathsConfig.app.accountFinance, account),
|
path: createPath(pathsConfig.app.accountFinance, account),
|
||||||
Icon: <Wallet className={iconClasses} />,
|
Icon: <Wallet className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.financeInvoices',
|
label: 'common.routes.financeInvoices',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountFinance + '/invoices',
|
pathsConfig.app.accountFinance + '/invoices',
|
||||||
account,
|
account,
|
||||||
@@ -266,12 +286,12 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <Receipt className={iconClasses} />,
|
Icon: <Receipt className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.financeSepa',
|
label: 'common.routes.financeSepa',
|
||||||
path: createPath(pathsConfig.app.accountFinance + '/sepa', account),
|
path: createPath(pathsConfig.app.accountFinance + '/sepa', account),
|
||||||
Icon: <Landmark className={iconClasses} />,
|
Icon: <Landmark className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.financePayments',
|
label: 'common.routes.financePayments',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountFinance + '/payments',
|
pathsConfig.app.accountFinance + '/payments',
|
||||||
account,
|
account,
|
||||||
@@ -285,16 +305,17 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Documents ──
|
// ── Documents ──
|
||||||
if (featureFlagsConfig.enableDocumentGeneration) {
|
if (featureFlagsConfig.enableDocumentGeneration) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.documentManagement',
|
label: 'common.routes.documentManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.documentOverview',
|
label: 'common.routes.documentOverview',
|
||||||
path: createPath(pathsConfig.app.accountDocuments, account),
|
path: createPath(pathsConfig.app.accountDocuments, account),
|
||||||
Icon: <FileText className={iconClasses} />,
|
Icon: <FileText className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.documentGenerate',
|
label: 'common.routes.documentGenerate',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountDocuments + '/generate',
|
pathsConfig.app.accountDocuments + '/generate',
|
||||||
account,
|
account,
|
||||||
@@ -302,7 +323,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <FilePlus className={iconClasses} />,
|
Icon: <FilePlus className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.documentTemplates',
|
label: 'common.routes.documentTemplates',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountDocuments + '/templates',
|
pathsConfig.app.accountDocuments + '/templates',
|
||||||
account,
|
account,
|
||||||
@@ -310,7 +331,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <FileStack className={iconClasses} />,
|
Icon: <FileStack className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.files',
|
label: 'common.routes.files',
|
||||||
path: createPath(pathsConfig.app.accountFiles, account),
|
path: createPath(pathsConfig.app.accountFiles, account),
|
||||||
Icon: <FolderOpen className={iconClasses} />,
|
Icon: <FolderOpen className={iconClasses} />,
|
||||||
},
|
},
|
||||||
@@ -321,21 +342,22 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Newsletter ──
|
// ── Newsletter ──
|
||||||
if (featureFlagsConfig.enableNewsletter) {
|
if (featureFlagsConfig.enableNewsletter) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.newsletterManagement',
|
label: 'common.routes.newsletterManagement',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.newsletterCampaigns',
|
label: 'common.routes.newsletterCampaigns',
|
||||||
path: createPath(pathsConfig.app.accountNewsletter, account),
|
path: createPath(pathsConfig.app.accountNewsletter, account),
|
||||||
Icon: <Mail className={iconClasses} />,
|
Icon: <Mail className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.newsletterNew',
|
label: 'common.routes.newsletterNew',
|
||||||
path: createPath(pathsConfig.app.accountNewsletter + '/new', account),
|
path: createPath(pathsConfig.app.accountNewsletter + '/new', account),
|
||||||
Icon: <MailPlus className={iconClasses} />,
|
Icon: <MailPlus className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.newsletterTemplates',
|
label: 'common.routes.newsletterTemplates',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountNewsletter + '/templates',
|
pathsConfig.app.accountNewsletter + '/templates',
|
||||||
account,
|
account,
|
||||||
@@ -349,16 +371,17 @@ const getRoutes = (account: string) => {
|
|||||||
// ── Site Builder ──
|
// ── Site Builder ──
|
||||||
if (featureFlagsConfig.enableSiteBuilder) {
|
if (featureFlagsConfig.enableSiteBuilder) {
|
||||||
routes.push({
|
routes.push({
|
||||||
label: 'common:routes.siteBuilder',
|
label: 'common.routes.siteBuilder',
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'common:routes.sitePages',
|
label: 'common.routes.sitePages',
|
||||||
path: createPath(pathsConfig.app.accountSiteBuilder, account),
|
path: createPath(pathsConfig.app.accountSiteBuilder, account),
|
||||||
Icon: <PanelTop className={iconClasses} />,
|
Icon: <PanelTop className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.sitePosts',
|
label: 'common.routes.sitePosts',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountSiteBuilder + '/posts',
|
pathsConfig.app.accountSiteBuilder + '/posts',
|
||||||
account,
|
account,
|
||||||
@@ -366,7 +389,7 @@ const getRoutes = (account: string) => {
|
|||||||
Icon: <Newspaper className={iconClasses} />,
|
Icon: <Newspaper className={iconClasses} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common:routes.siteSettings',
|
label: 'common.routes.siteSettings',
|
||||||
path: createPath(
|
path: createPath(
|
||||||
pathsConfig.app.accountSiteBuilder + '/settings',
|
pathsConfig.app.accountSiteBuilder + '/settings',
|
||||||
account,
|
account,
|
||||||
@@ -377,58 +400,189 @@ const getRoutes = (account: string) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Fischerei, Meetings, and Verband sections are injected at runtime
|
// ── Custom Modules ──
|
||||||
// via injectAccountFeatureRoutes() in the layout, based on per-account
|
if (featureFlagsConfig.enableModuleBuilder) {
|
||||||
// settings (account_settings.features). They are NOT added here to avoid
|
routes.push({
|
||||||
// duplicate entries when both the global feature flag and per-account
|
label: 'common.routes.customModules',
|
||||||
// setting are enabled.
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'common.routes.moduleList',
|
||||||
|
path: createPath(pathsConfig.app.accountModules, account),
|
||||||
|
Icon: <Database className={iconClasses} />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Fisheries ──
|
||||||
|
if (featureFlagsConfig.enableFischerei && (accountFeatures?.fischerei !== false)) {
|
||||||
|
routes.push({
|
||||||
|
label: 'common.routes.fisheriesManagement',
|
||||||
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesOverview',
|
||||||
|
path: createPath(pathsConfig.app.accountFischerei, account),
|
||||||
|
Icon: <Fish className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesWaters',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountFischerei + '/waters',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <Waves className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesLeases',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountFischerei + '/leases',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <Anchor className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesCatchBooks',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountFischerei + '/catch-books',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <BookOpen className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesPermits',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountFischerei + '/permits',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <ShieldCheck className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.fisheriesCompetitions',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountFischerei + '/competitions',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <Trophy className={iconClasses} />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Meeting Protocols ──
|
||||||
|
if (featureFlagsConfig.enableMeetingProtocols && (accountFeatures?.meetings !== false)) {
|
||||||
|
routes.push({
|
||||||
|
label: 'common.routes.meetingProtocols',
|
||||||
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'common.routes.meetingsOverview',
|
||||||
|
path: createPath(pathsConfig.app.accountMeetings, account),
|
||||||
|
Icon: <BookMarked className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.meetingsProtocols',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountMeetings + '/protocols',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <ScrollText className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.meetingsTasks',
|
||||||
|
path: createPath(pathsConfig.app.accountMeetings + '/tasks', account),
|
||||||
|
Icon: <ListChecks className={iconClasses} />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Association Management (Verband) ──
|
||||||
|
if (featureFlagsConfig.enableVerbandsverwaltung && (accountFeatures?.verband !== false)) {
|
||||||
|
routes.push({
|
||||||
|
label: 'common.routes.associationManagement',
|
||||||
|
collapsible: true,
|
||||||
|
collapsed: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationOverview',
|
||||||
|
path: createPath(pathsConfig.app.accountVerband, account),
|
||||||
|
Icon: <Building2 className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationHierarchy',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountVerband + '/hierarchy',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <Network className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationMemberSearch',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountVerband + '/members',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <SearchCheck className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationEvents',
|
||||||
|
path: createPath(pathsConfig.app.accountVerband + '/events', account),
|
||||||
|
Icon: <Share2 className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationReporting',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountVerband + '/reporting',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <PieChart className={iconClasses} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.routes.associationTemplates',
|
||||||
|
path: createPath(
|
||||||
|
pathsConfig.app.accountVerband + '/templates',
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
Icon: <LayoutTemplate className={iconClasses} />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ── Administration ──
|
// ── Administration ──
|
||||||
{
|
routes.push({
|
||||||
const adminChildren: Array<
|
label: 'common.routes.administration',
|
||||||
| {
|
collapsible: false,
|
||||||
label: string;
|
children: [
|
||||||
path: string;
|
|
||||||
Icon: React.ReactNode;
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
> = [
|
|
||||||
{
|
{
|
||||||
label: 'common:routes.accountSettings',
|
label: 'common.routes.accountSettings',
|
||||||
path: createPath(pathsConfig.app.accountSettings, account),
|
path: createPath(pathsConfig.app.accountSettings, account),
|
||||||
Icon: <Settings className={iconClasses} />,
|
Icon: <Settings className={iconClasses} />,
|
||||||
},
|
},
|
||||||
];
|
featureFlagsConfig.enableTeamAccountBilling
|
||||||
|
? {
|
||||||
if (featureFlagsConfig.enableModuleBuilder) {
|
label: 'common.routes.billing',
|
||||||
adminChildren.push({
|
path: createPath(pathsConfig.app.accountBilling, account),
|
||||||
label: 'common:routes.moduleList',
|
Icon: <CreditCard className={iconClasses} />,
|
||||||
path: createPath(pathsConfig.app.accountModules, account),
|
}
|
||||||
Icon: <Database className={iconClasses} />,
|
: undefined,
|
||||||
});
|
],
|
||||||
}
|
});
|
||||||
|
|
||||||
if (featureFlagsConfig.enableTeamAccountBilling) {
|
|
||||||
adminChildren.push({
|
|
||||||
label: 'common:routes.billing',
|
|
||||||
path: createPath(pathsConfig.app.accountBilling, account),
|
|
||||||
Icon: <CreditCard className={iconClasses} />,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
routes.push({
|
|
||||||
label: 'common:routes.administration',
|
|
||||||
collapsible: false,
|
|
||||||
children: adminChildren,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getTeamAccountSidebarConfig(account: string) {
|
export function getTeamAccountSidebarConfig(
|
||||||
|
account: string,
|
||||||
|
accountFeatures?: Record<string, boolean>,
|
||||||
|
) {
|
||||||
return NavigationConfigSchema.parse({
|
return NavigationConfigSchema.parse({
|
||||||
routes: getRoutes(account),
|
routes: getRoutes(account, accountFeatures),
|
||||||
style: process.env.NEXT_PUBLIC_TEAM_NAVIGATION_STYLE,
|
style: process.env.NEXT_PUBLIC_TEAM_NAVIGATION_STYLE,
|
||||||
sidebarCollapsed: process.env.NEXT_PUBLIC_TEAM_SIDEBAR_COLLAPSED,
|
sidebarCollapsed: process.env.NEXT_PUBLIC_TEAM_SIDEBAR_COLLAPSED,
|
||||||
sidebarCollapsedStyle: process.env.NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE,
|
sidebarCollapsedStyle: process.env.NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE,
|
||||||
|
|||||||
@@ -170,7 +170,7 @@
|
|||||||
},
|
},
|
||||||
"events": {
|
"events": {
|
||||||
"title": "Veranstaltungen",
|
"title": "Veranstaltungen",
|
||||||
"description": "Beschreibung",
|
"description": "Veranstaltungen planen, verwalten und Anmeldungen erfassen",
|
||||||
"newEvent": "Neue Veranstaltung",
|
"newEvent": "Neue Veranstaltung",
|
||||||
"registrations": "Anmeldungen",
|
"registrations": "Anmeldungen",
|
||||||
"holidayPasses": "Ferienpässe",
|
"holidayPasses": "Ferienpässe",
|
||||||
|
|||||||
@@ -137,7 +137,9 @@
|
|||||||
"associationReporting": "Berichte",
|
"associationReporting": "Berichte",
|
||||||
"associationTemplates": "Geteilte Vorlagen",
|
"associationTemplates": "Geteilte Vorlagen",
|
||||||
"administration": "Administration",
|
"administration": "Administration",
|
||||||
"accountSettings": "Kontoeinstellungen"
|
"accountSettings": "Kontoeinstellungen",
|
||||||
|
"application": "Anwendung",
|
||||||
|
"home": "Startseite"
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"owner": {
|
"owner": {
|
||||||
@@ -219,5 +221,6 @@
|
|||||||
"title": "Konto nicht gefunden",
|
"title": "Konto nicht gefunden",
|
||||||
"description": "Das angeforderte Konto existiert nicht oder Sie haben keine Berechtigung darauf zuzugreifen.",
|
"description": "Das angeforderte Konto existiert nicht oder Sie haben keine Berechtigung darauf zuzugreifen.",
|
||||||
"action": "Zum Dashboard"
|
"action": "Zum Dashboard"
|
||||||
}
|
},
|
||||||
|
"confirm": "Bestätigen"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,7 +170,7 @@
|
|||||||
},
|
},
|
||||||
"events": {
|
"events": {
|
||||||
"title": "Events",
|
"title": "Events",
|
||||||
"description": "Description",
|
"description": "Plan, manage, and track event registrations",
|
||||||
"newEvent": "New Event",
|
"newEvent": "New Event",
|
||||||
"registrations": "Registrations",
|
"registrations": "Registrations",
|
||||||
"holidayPasses": "Holiday Passes",
|
"holidayPasses": "Holiday Passes",
|
||||||
|
|||||||
@@ -138,7 +138,8 @@
|
|||||||
"associationReporting": "Reports",
|
"associationReporting": "Reports",
|
||||||
"associationTemplates": "Shared Templates",
|
"associationTemplates": "Shared Templates",
|
||||||
"administration": "Administration",
|
"administration": "Administration",
|
||||||
"accountSettings": "Account Settings"
|
"accountSettings": "Account Settings",
|
||||||
|
"application": "Application"
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"owner": {
|
"owner": {
|
||||||
@@ -220,5 +221,6 @@
|
|||||||
"title": "Account not found",
|
"title": "Account not found",
|
||||||
"description": "The requested account does not exist or you do not have permission to access it.",
|
"description": "The requested account does not exist or you do not have permission to access it.",
|
||||||
"action": "Go to Dashboard"
|
"action": "Go to Dashboard"
|
||||||
}
|
},
|
||||||
|
"confirm": "Confirm"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ async function migrateAccounts(
|
|||||||
|
|
||||||
onProgress?.('Creating team accounts', Object.keys(TENANT_MAPPING).length);
|
onProgress?.('Creating team accounts', Object.keys(TENANT_MAPPING).length);
|
||||||
|
|
||||||
for (const [profileId, config] of Object.entries(TENANT_MAPPING)) {
|
for (const [profileId, _config] of Object.entries(TENANT_MAPPING)) {
|
||||||
try {
|
try {
|
||||||
// Create account_settings entry for each tenant
|
// Create account_settings entry for each tenant
|
||||||
result.count++;
|
result.count++;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type { Factor } from '@supabase/supabase-js';
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { Fingerprint, KeyRound, TriangleAlert } from 'lucide-react';
|
import { Fingerprint, KeyRound, TriangleAlert } from 'lucide-react';
|
||||||
import { useForm, useWatch } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import * as z from 'zod';
|
import * as z from 'zod';
|
||||||
|
|
||||||
import { useFetchAuthFactors } from '@kit/supabase/hooks/use-fetch-mfa-factors';
|
import { useFetchAuthFactors } from '@kit/supabase/hooks/use-fetch-mfa-factors';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { createBookingManagementApi } from '../api';
|
|||||||
|
|
||||||
export const createBooking = authActionClient
|
export const createBooking = authActionClient
|
||||||
.inputSchema(CreateBookingSchema)
|
.inputSchema(CreateBookingSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createBookingManagementApi(client);
|
const api = createBookingManagementApi(client);
|
||||||
@@ -33,7 +33,7 @@ export const updateBookingStatus = authActionClient
|
|||||||
status: z.string(),
|
status: z.string(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createBookingManagementApi(client);
|
const api = createBookingManagementApi(client);
|
||||||
@@ -46,7 +46,7 @@ export const updateBookingStatus = authActionClient
|
|||||||
|
|
||||||
export const createRoom = authActionClient
|
export const createRoom = authActionClient
|
||||||
.inputSchema(CreateRoomSchema)
|
.inputSchema(CreateRoomSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createBookingManagementApi(client);
|
const api = createBookingManagementApi(client);
|
||||||
@@ -59,7 +59,7 @@ export const createRoom = authActionClient
|
|||||||
|
|
||||||
export const createGuest = authActionClient
|
export const createGuest = authActionClient
|
||||||
.inputSchema(CreateGuestSchema)
|
.inputSchema(CreateGuestSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createBookingManagementApi(client);
|
const api = createBookingManagementApi(client);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type { CreateBookingInput } from '../schema/booking.schema';
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
export function createBookingManagementApi(client: SupabaseClient<Database>) {
|
export function createBookingManagementApi(client: SupabaseClient<Database>) {
|
||||||
const db = client;
|
const _db = client;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// --- Rooms ---
|
// --- Rooms ---
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { createCourseManagementApi } from '../api';
|
|||||||
|
|
||||||
export const createCourse = authActionClient
|
export const createCourse = authActionClient
|
||||||
.inputSchema(CreateCourseSchema)
|
.inputSchema(CreateCourseSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -32,7 +32,7 @@ export const createCourse = authActionClient
|
|||||||
|
|
||||||
export const updateCourse = authActionClient
|
export const updateCourse = authActionClient
|
||||||
.inputSchema(UpdateCourseSchema)
|
.inputSchema(UpdateCourseSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -45,7 +45,7 @@ export const updateCourse = authActionClient
|
|||||||
|
|
||||||
export const deleteCourse = authActionClient
|
export const deleteCourse = authActionClient
|
||||||
.inputSchema(z.object({ courseId: z.string().uuid() }))
|
.inputSchema(z.object({ courseId: z.string().uuid() }))
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -58,7 +58,7 @@ export const deleteCourse = authActionClient
|
|||||||
|
|
||||||
export const enrollParticipant = authActionClient
|
export const enrollParticipant = authActionClient
|
||||||
.inputSchema(EnrollParticipantSchema)
|
.inputSchema(EnrollParticipantSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -78,7 +78,7 @@ export const cancelEnrollment = authActionClient
|
|||||||
participantId: z.string().uuid(),
|
participantId: z.string().uuid(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -100,7 +100,7 @@ export const markAttendance = authActionClient
|
|||||||
present: z.boolean(),
|
present: z.boolean(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -117,7 +117,7 @@ export const markAttendance = authActionClient
|
|||||||
|
|
||||||
export const createCategory = authActionClient
|
export const createCategory = authActionClient
|
||||||
.inputSchema(CreateCategorySchema)
|
.inputSchema(CreateCategorySchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -130,7 +130,7 @@ export const createCategory = authActionClient
|
|||||||
|
|
||||||
export const createInstructor = authActionClient
|
export const createInstructor = authActionClient
|
||||||
.inputSchema(CreateInstructorSchema)
|
.inputSchema(CreateInstructorSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -143,7 +143,7 @@ export const createInstructor = authActionClient
|
|||||||
|
|
||||||
export const createLocation = authActionClient
|
export const createLocation = authActionClient
|
||||||
.inputSchema(CreateLocationSchema)
|
.inputSchema(CreateLocationSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
@@ -156,7 +156,7 @@ export const createLocation = authActionClient
|
|||||||
|
|
||||||
export const createSession = authActionClient
|
export const createSession = authActionClient
|
||||||
.inputSchema(CreateSessionSchema)
|
.inputSchema(CreateSessionSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createCourseManagementApi(client);
|
const api = createCourseManagementApi(client);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type {
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
export function createCourseManagementApi(client: SupabaseClient<Database>) {
|
export function createCourseManagementApi(client: SupabaseClient<Database>) {
|
||||||
const db = client;
|
const _db = client;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// --- Courses ---
|
// --- Courses ---
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function createDocumentGeneratorApi() {
|
|||||||
* Generate a PDF document (member card, invoice, certificate, etc.)
|
* Generate a PDF document (member card, invoice, certificate, etc.)
|
||||||
* Uses @react-pdf/renderer or jspdf at runtime.
|
* Uses @react-pdf/renderer or jspdf at runtime.
|
||||||
*/
|
*/
|
||||||
async generatePdf(params: {
|
async generatePdf(_params: {
|
||||||
title: string;
|
title: string;
|
||||||
content: Record<string, unknown>;
|
content: Record<string, unknown>;
|
||||||
format?: 'A4' | 'A5' | 'letter';
|
format?: 'A4' | 'A5' | 'letter';
|
||||||
@@ -28,7 +28,7 @@ export function createDocumentGeneratorApi() {
|
|||||||
* Generate an Excel workbook (reports, data exports)
|
* Generate an Excel workbook (reports, data exports)
|
||||||
* Uses exceljs at runtime.
|
* Uses exceljs at runtime.
|
||||||
*/
|
*/
|
||||||
async generateExcel(params: {
|
async generateExcel(_params: {
|
||||||
title: string;
|
title: string;
|
||||||
sheets: Array<{
|
sheets: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
@@ -45,7 +45,7 @@ export function createDocumentGeneratorApi() {
|
|||||||
* Generate a Word document (mail merge, letters)
|
* Generate a Word document (mail merge, letters)
|
||||||
* Uses docx at runtime.
|
* Uses docx at runtime.
|
||||||
*/
|
*/
|
||||||
async generateWord(params: {
|
async generateWord(_params: {
|
||||||
title: string;
|
title: string;
|
||||||
templateContent: string;
|
templateContent: string;
|
||||||
mergeFields: Record<string, string>;
|
mergeFields: Record<string, string>;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { createEventManagementApi } from '../api';
|
|||||||
|
|
||||||
export const createEvent = authActionClient
|
export const createEvent = authActionClient
|
||||||
.inputSchema(CreateEventSchema)
|
.inputSchema(CreateEventSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createEventManagementApi(client);
|
const api = createEventManagementApi(client);
|
||||||
@@ -29,7 +29,7 @@ export const createEvent = authActionClient
|
|||||||
|
|
||||||
export const updateEvent = authActionClient
|
export const updateEvent = authActionClient
|
||||||
.inputSchema(UpdateEventSchema)
|
.inputSchema(UpdateEventSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createEventManagementApi(client);
|
const api = createEventManagementApi(client);
|
||||||
@@ -42,7 +42,7 @@ export const updateEvent = authActionClient
|
|||||||
|
|
||||||
export const deleteEvent = authActionClient
|
export const deleteEvent = authActionClient
|
||||||
.inputSchema(z.object({ eventId: z.string().uuid() }))
|
.inputSchema(z.object({ eventId: z.string().uuid() }))
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createEventManagementApi(client);
|
const api = createEventManagementApi(client);
|
||||||
@@ -55,7 +55,7 @@ export const deleteEvent = authActionClient
|
|||||||
|
|
||||||
export const registerForEvent = authActionClient
|
export const registerForEvent = authActionClient
|
||||||
.inputSchema(EventRegistrationSchema)
|
.inputSchema(EventRegistrationSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createEventManagementApi(client);
|
const api = createEventManagementApi(client);
|
||||||
@@ -68,7 +68,7 @@ export const registerForEvent = authActionClient
|
|||||||
|
|
||||||
export const createHolidayPass = authActionClient
|
export const createHolidayPass = authActionClient
|
||||||
.inputSchema(CreateHolidayPassSchema)
|
.inputSchema(CreateHolidayPassSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createEventManagementApi(client);
|
const api = createEventManagementApi(client);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type {
|
|||||||
|
|
||||||
export function createEventManagementApi(client: SupabaseClient<Database>) {
|
export function createEventManagementApi(client: SupabaseClient<Database>) {
|
||||||
const PAGE_SIZE = 25;
|
const PAGE_SIZE = 25;
|
||||||
const db = client;
|
const _db = client;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async listEvents(
|
async listEvents(
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { createFinanceApi } from '../api';
|
|||||||
|
|
||||||
export const createSepaBatch = authActionClient
|
export const createSepaBatch = authActionClient
|
||||||
.inputSchema(CreateSepaBatchSchema)
|
.inputSchema(CreateSepaBatchSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFinanceApi(client);
|
const api = createFinanceApi(client);
|
||||||
@@ -29,7 +29,7 @@ export const createSepaBatch = authActionClient
|
|||||||
|
|
||||||
export const addSepaItem = authActionClient
|
export const addSepaItem = authActionClient
|
||||||
.inputSchema(AddSepaItemSchema)
|
.inputSchema(AddSepaItemSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFinanceApi(client);
|
const api = createFinanceApi(client);
|
||||||
@@ -51,7 +51,7 @@ export const generateSepaXml = authActionClient
|
|||||||
creditorId: z.string(),
|
creditorId: z.string(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFinanceApi(client);
|
const api = createFinanceApi(client);
|
||||||
@@ -76,7 +76,7 @@ export const generateSepaXml = authActionClient
|
|||||||
|
|
||||||
export const createInvoice = authActionClient
|
export const createInvoice = authActionClient
|
||||||
.inputSchema(CreateInvoiceSchema)
|
.inputSchema(CreateInvoiceSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFinanceApi(client);
|
const api = createFinanceApi(client);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
export function createFinanceApi(client: SupabaseClient<Database>) {
|
export function createFinanceApi(client: SupabaseClient<Database>) {
|
||||||
const db = client;
|
const _db = client;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// --- SEPA Batches ---
|
// --- SEPA Batches ---
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Pencil, Plus } from 'lucide-react';
|
|||||||
|
|
||||||
import { formatDate } from '@kit/shared/dates';
|
import { formatDate } from '@kit/shared/dates';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
import { Card, CardContent } from '@kit/ui/card';
|
||||||
import { useActionWithToast } from '@kit/ui/use-action-with-toast';
|
import { useActionWithToast } from '@kit/ui/use-action-with-toast';
|
||||||
|
|
||||||
import { deleteCompetition } from '../server/actions/fischerei-actions';
|
import { deleteCompetition } from '../server/actions/fischerei-actions';
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { useRouter, useSearchParams } from 'next/navigation';
|
|||||||
import { Pencil, Plus } from 'lucide-react';
|
import { Pencil, Plus } from 'lucide-react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { Badge } from '@kit/ui/badge';
|
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
||||||
import { Input } from '@kit/ui/input';
|
import { Input } from '@kit/ui/input';
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ import Link from 'next/link';
|
|||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
|
|
||||||
import { Pencil, Plus } from 'lucide-react';
|
import { Pencil, Plus } from 'lucide-react';
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
|
|
||||||
import { formatDate } from '@kit/shared/dates';
|
import { formatDate } from '@kit/shared/dates';
|
||||||
import { formatNumber, formatCurrencyAmount } from '@kit/shared/formatters';
|
import { formatNumber, formatCurrencyAmount } from '@kit/shared/formatters';
|
||||||
import { Badge } from '@kit/ui/badge';
|
import { Badge } from '@kit/ui/badge';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
import { Card, CardContent } from '@kit/ui/card';
|
||||||
import { Input } from '@kit/ui/input';
|
|
||||||
import { useActionWithToast } from '@kit/ui/use-action-with-toast';
|
import { useActionWithToast } from '@kit/ui/use-action-with-toast';
|
||||||
|
|
||||||
import { AGE_CLASS_LABELS } from '../lib/fischerei-constants';
|
import { AGE_CLASS_LABELS } from '../lib/fischerei-constants';
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import {
|
|||||||
CreateCompetitionParticipantSchema,
|
CreateCompetitionParticipantSchema,
|
||||||
CreateSupplierSchema,
|
CreateSupplierSchema,
|
||||||
UpdateSupplierSchema,
|
UpdateSupplierSchema,
|
||||||
catchBookStatusSchema,
|
|
||||||
catchBookVerificationSchema,
|
catchBookVerificationSchema,
|
||||||
} from '../../schema/fischerei.schema';
|
} from '../../schema/fischerei.schema';
|
||||||
import { createFischereiApi } from '../api';
|
import { createFischereiApi } from '../api';
|
||||||
@@ -40,7 +39,7 @@ import { createFischereiApi } from '../api';
|
|||||||
|
|
||||||
export const createWater = authActionClient
|
export const createWater = authActionClient
|
||||||
.inputSchema(CreateWaterSchema)
|
.inputSchema(CreateWaterSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -55,7 +54,7 @@ export const createWater = authActionClient
|
|||||||
|
|
||||||
export const updateWater = authActionClient
|
export const updateWater = authActionClient
|
||||||
.inputSchema(UpdateWaterSchema)
|
.inputSchema(UpdateWaterSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -192,7 +191,7 @@ export const deleteWaterSpeciesRule = authActionClient
|
|||||||
|
|
||||||
export const createStocking = authActionClient
|
export const createStocking = authActionClient
|
||||||
.inputSchema(CreateStockingSchema)
|
.inputSchema(CreateStockingSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -213,7 +212,7 @@ export const createStocking = authActionClient
|
|||||||
|
|
||||||
export const updateStocking = authActionClient
|
export const updateStocking = authActionClient
|
||||||
.inputSchema(UpdateStockingSchema)
|
.inputSchema(UpdateStockingSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -263,7 +262,7 @@ export const deleteStocking = authActionClient
|
|||||||
|
|
||||||
export const createLease = authActionClient
|
export const createLease = authActionClient
|
||||||
.inputSchema(CreateLeaseSchema)
|
.inputSchema(CreateLeaseSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -278,7 +277,7 @@ export const createLease = authActionClient
|
|||||||
|
|
||||||
export const updateLease = authActionClient
|
export const updateLease = authActionClient
|
||||||
.inputSchema(UpdateLeaseSchema)
|
.inputSchema(UpdateLeaseSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -316,7 +315,7 @@ export const deleteLease = authActionClient
|
|||||||
|
|
||||||
export const createCatchBook = authActionClient
|
export const createCatchBook = authActionClient
|
||||||
.inputSchema(CreateCatchBookSchema)
|
.inputSchema(CreateCatchBookSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -334,7 +333,7 @@ export const createCatchBook = authActionClient
|
|||||||
|
|
||||||
export const updateCatchBook = authActionClient
|
export const updateCatchBook = authActionClient
|
||||||
.inputSchema(UpdateCatchBookSchema)
|
.inputSchema(UpdateCatchBookSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -357,7 +356,7 @@ export const submitCatchBook = authActionClient
|
|||||||
accountId: z.string().uuid(),
|
accountId: z.string().uuid(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -383,7 +382,7 @@ export const reviewCatchBook = authActionClient
|
|||||||
remarks: z.string().optional(),
|
remarks: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -581,7 +580,7 @@ export const removeInspector = authActionClient
|
|||||||
|
|
||||||
export const createCompetition = authActionClient
|
export const createCompetition = authActionClient
|
||||||
.inputSchema(CreateCompetitionSchema)
|
.inputSchema(CreateCompetitionSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
@@ -602,7 +601,7 @@ export const createCompetition = authActionClient
|
|||||||
|
|
||||||
export const updateCompetition = authActionClient
|
export const updateCompetition = authActionClient
|
||||||
.inputSchema(UpdateCompetitionSchema)
|
.inputSchema(UpdateCompetitionSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createFischereiApi(client);
|
const api = createFischereiApi(client);
|
||||||
|
|||||||
@@ -1154,7 +1154,7 @@ export function createFischereiApi(client: SupabaseClient<Database>) {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateCompetition(input: UpdateCompetitionInput, userId: string) {
|
async updateCompetition(input: UpdateCompetitionInput, _userId: string) {
|
||||||
const updateData: Record<string, unknown> = {};
|
const updateData: Record<string, unknown> = {};
|
||||||
|
|
||||||
if (input.name !== undefined) updateData.name = input.name;
|
if (input.name !== undefined) updateData.name = input.name;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface ApplicationWorkflowProps {
|
|||||||
export function ApplicationWorkflow({
|
export function ApplicationWorkflow({
|
||||||
applications,
|
applications,
|
||||||
accountId,
|
accountId,
|
||||||
account,
|
account: _account,
|
||||||
}: ApplicationWorkflowProps) {
|
}: ApplicationWorkflowProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ interface MandateManagerProps {
|
|||||||
accountId: string;
|
accountId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEQUENCE_LABELS: Record<string, string> = {
|
const _SEQUENCE_LABELS: Record<string, string> = {
|
||||||
FRST: 'Erstlastschrift',
|
FRST: 'Erstlastschrift',
|
||||||
RCUR: 'Wiederkehrend',
|
RCUR: 'Wiederkehrend',
|
||||||
FNAL: 'Letzte',
|
FNAL: 'Letzte',
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export function MembersDataTable({
|
|||||||
pageSize,
|
pageSize,
|
||||||
account,
|
account,
|
||||||
accountId,
|
accountId,
|
||||||
duesCategories,
|
duesCategories: _duesCategories,
|
||||||
}: MembersDataTableProps) {
|
}: MembersDataTableProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { createMemberManagementApi } from '../api';
|
|||||||
|
|
||||||
export const createMember = authActionClient
|
export const createMember = authActionClient
|
||||||
.inputSchema(CreateMemberSchema)
|
.inputSchema(CreateMemberSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
@@ -58,7 +58,7 @@ export const createMember = authActionClient
|
|||||||
|
|
||||||
export const updateMember = authActionClient
|
export const updateMember = authActionClient
|
||||||
.inputSchema(UpdateMemberSchema)
|
.inputSchema(UpdateMemberSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
@@ -77,7 +77,7 @@ export const deleteMember = authActionClient
|
|||||||
accountId: z.string().uuid(),
|
accountId: z.string().uuid(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
@@ -95,7 +95,7 @@ export const approveApplication = authActionClient
|
|||||||
accountId: z.string().uuid(),
|
accountId: z.string().uuid(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
@@ -112,7 +112,7 @@ export const approveApplication = authActionClient
|
|||||||
|
|
||||||
export const rejectApplication = authActionClient
|
export const rejectApplication = authActionClient
|
||||||
.inputSchema(RejectApplicationSchema)
|
.inputSchema(RejectApplicationSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
@@ -297,7 +297,7 @@ export const generateMemberCards = authActionClient
|
|||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input }) => {
|
.action(async ({ parsedInput: input }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const api = createMemberManagementApi(client);
|
const _api = createMemberManagementApi(client);
|
||||||
|
|
||||||
let query = client
|
let query = client
|
||||||
.from('members')
|
.from('members')
|
||||||
@@ -342,7 +342,7 @@ export const inviteMemberToPortal = authActionClient
|
|||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createMemberManagementApi(client);
|
const api = createMemberManagementApi(client);
|
||||||
|
|||||||
@@ -9,13 +9,12 @@ import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
|||||||
import {
|
import {
|
||||||
CreateNewsletterSchema,
|
CreateNewsletterSchema,
|
||||||
UpdateNewsletterSchema,
|
UpdateNewsletterSchema,
|
||||||
CreateTemplateSchema,
|
|
||||||
} from '../../schema/newsletter.schema';
|
} from '../../schema/newsletter.schema';
|
||||||
import { createNewsletterApi } from '../api';
|
import { createNewsletterApi } from '../api';
|
||||||
|
|
||||||
export const createNewsletter = authActionClient
|
export const createNewsletter = authActionClient
|
||||||
.inputSchema(CreateNewsletterSchema)
|
.inputSchema(CreateNewsletterSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createNewsletterApi(client);
|
const api = createNewsletterApi(client);
|
||||||
@@ -29,7 +28,7 @@ export const createNewsletter = authActionClient
|
|||||||
|
|
||||||
export const updateNewsletter = authActionClient
|
export const updateNewsletter = authActionClient
|
||||||
.inputSchema(UpdateNewsletterSchema)
|
.inputSchema(UpdateNewsletterSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createNewsletterApi(client);
|
const api = createNewsletterApi(client);
|
||||||
@@ -51,7 +50,7 @@ export const createTemplate = authActionClient
|
|||||||
variables: z.array(z.string()).optional(),
|
variables: z.array(z.string()).optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createNewsletterApi(client);
|
const api = createNewsletterApi(client);
|
||||||
@@ -74,7 +73,7 @@ export const addRecipients = authActionClient
|
|||||||
.optional(),
|
.optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createNewsletterApi(client);
|
const api = createNewsletterApi(client);
|
||||||
@@ -95,7 +94,7 @@ export const dispatchNewsletter = authActionClient
|
|||||||
newsletterId: z.string().uuid(),
|
newsletterId: z.string().uuid(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const logger = await getLogger();
|
const logger = await getLogger();
|
||||||
const api = createNewsletterApi(client);
|
const api = createNewsletterApi(client);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function substituteVariables(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createNewsletterApi(client: SupabaseClient<Database>) {
|
export function createNewsletterApi(client: SupabaseClient<Database>) {
|
||||||
const db = client;
|
const _db = client;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// --- Templates ---
|
// --- Templates ---
|
||||||
@@ -254,7 +254,7 @@ export function createNewsletterApi(client: SupabaseClient<Database>) {
|
|||||||
for (const recipient of pending) {
|
for (const recipient of pending) {
|
||||||
try {
|
try {
|
||||||
// Substitute variables in the body
|
// Substitute variables in the body
|
||||||
const personalizedHtml = substituteVariables(newsletter.body_html, {
|
const _personalizedHtml = substituteVariables(newsletter.body_html, {
|
||||||
first_name: (recipient.name ?? '').split(' ')[0] ?? '',
|
first_name: (recipient.name ?? '').split(' ')[0] ?? '',
|
||||||
name: recipient.name ?? '',
|
name: recipient.name ?? '',
|
||||||
email: recipient.email ?? '',
|
email: recipient.email ?? '',
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export function PortalLoginForm({ slug, accountName }: Props) {
|
|||||||
router.push(`/club/${slug}/portal/profile`);
|
router.push(`/club/${slug}/portal/profile`);
|
||||||
router.refresh();
|
router.refresh();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
setError('Verbindungsfehler. Bitte versuchen Sie es erneut.');
|
setError('Verbindungsfehler. Bitte versuchen Sie es erneut.');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface Props {
|
|||||||
initialData: Record<string, unknown>;
|
initialData: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SiteEditor({ pageId, accountId, initialData }: Props) {
|
export function SiteEditor({ pageId, accountId: _accountId, initialData }: Props) {
|
||||||
const { execute: execPublish } = useActionWithToast(publishPage, {
|
const { execute: execPublish } = useActionWithToast(publishPage, {
|
||||||
successMessage: 'Seite veröffentlicht',
|
successMessage: 'Seite veröffentlicht',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ const ContactFormBlock = ({
|
|||||||
const MapBlock = ({
|
const MapBlock = ({
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
zoom,
|
zoom: _zoom,
|
||||||
height,
|
height,
|
||||||
}: {
|
}: {
|
||||||
latitude: number;
|
latitude: number;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { authActionClient } from '@kit/next/safe-action';
|
import { authActionClient } from '@kit/next/safe-action';
|
||||||
import { getLogger } from '@kit/shared/logger';
|
|
||||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -12,13 +11,12 @@ import {
|
|||||||
SiteSettingsSchema,
|
SiteSettingsSchema,
|
||||||
CreatePostSchema,
|
CreatePostSchema,
|
||||||
UpdatePostSchema,
|
UpdatePostSchema,
|
||||||
NewsletterSubscribeSchema,
|
|
||||||
} from '../../schema/site.schema';
|
} from '../../schema/site.schema';
|
||||||
import { createSiteBuilderApi } from '../api';
|
import { createSiteBuilderApi } from '../api';
|
||||||
|
|
||||||
export const createPage = authActionClient
|
export const createPage = authActionClient
|
||||||
.inputSchema(CreatePageSchema)
|
.inputSchema(CreatePageSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const api = createSiteBuilderApi(client);
|
const api = createSiteBuilderApi(client);
|
||||||
const data = await api.createPage(input, ctx.user.id);
|
const data = await api.createPage(input, ctx.user.id);
|
||||||
@@ -27,7 +25,7 @@ export const createPage = authActionClient
|
|||||||
|
|
||||||
export const saveDraft = authActionClient
|
export const saveDraft = authActionClient
|
||||||
.inputSchema(UpdatePageSchema)
|
.inputSchema(UpdatePageSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const api = createSiteBuilderApi(client);
|
const api = createSiteBuilderApi(client);
|
||||||
const data = await api.updatePage(
|
const data = await api.updatePage(
|
||||||
@@ -40,7 +38,7 @@ export const saveDraft = authActionClient
|
|||||||
|
|
||||||
export const publishPage = authActionClient
|
export const publishPage = authActionClient
|
||||||
.inputSchema(UpdatePageSchema)
|
.inputSchema(UpdatePageSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const api = createSiteBuilderApi(client);
|
const api = createSiteBuilderApi(client);
|
||||||
const data = await api.updatePage(
|
const data = await api.updatePage(
|
||||||
@@ -71,7 +69,7 @@ export const updateSiteSettings = authActionClient
|
|||||||
|
|
||||||
export const createPost = authActionClient
|
export const createPost = authActionClient
|
||||||
.inputSchema(CreatePostSchema)
|
.inputSchema(CreatePostSchema)
|
||||||
.action(async ({ parsedInput: input, ctx }) => {
|
.action(async ({ parsedInput: input, ctx: _ctx }) => {
|
||||||
const client = getSupabaseServerClient();
|
const client = getSupabaseServerClient();
|
||||||
const api = createSiteBuilderApi(client);
|
const api = createSiteBuilderApi(client);
|
||||||
const data = await api.createPost(input, ctx.user.id);
|
const data = await api.createPost(input, ctx.user.id);
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ const STATUS_TRANSITIONS: Record<string, MeetingItemStatus> = {
|
|||||||
|
|
||||||
export function ProtocolItemsList({
|
export function ProtocolItemsList({
|
||||||
items,
|
items,
|
||||||
protocolId,
|
protocolId: _protocolId,
|
||||||
account,
|
account: _account,
|
||||||
}: ProtocolItemsListProps) {
|
}: ProtocolItemsListProps) {
|
||||||
const { execute: executeStatusUpdate, isPending: isUpdating } = useAction(
|
const { execute: executeStatusUpdate, isPending: _isUpdating } = useAction(
|
||||||
updateItemStatus,
|
updateItemStatus,
|
||||||
{
|
{
|
||||||
onSuccess: ({ data }) => {
|
onSuccess: ({ data }) => {
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ export function createMeetingsApi(client: SupabaseClient<Database>) {
|
|||||||
return data ?? [];
|
return data ?? [];
|
||||||
},
|
},
|
||||||
|
|
||||||
async createItem(input: CreateProtocolItemInput, userId: string) {
|
async createItem(input: CreateProtocolItemInput, _userId: string) {
|
||||||
const { data, error } = await client
|
const { data, error } = await client
|
||||||
.from('meeting_protocol_items')
|
.from('meeting_protocol_items')
|
||||||
.insert({
|
.insert({
|
||||||
@@ -168,7 +168,7 @@ export function createMeetingsApi(client: SupabaseClient<Database>) {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateItem(input: UpdateProtocolItemInput, userId: string) {
|
async updateItem(input: UpdateProtocolItemInput, _userId: string) {
|
||||||
const updateData: Record<string, unknown> = {};
|
const updateData: Record<string, unknown> = {};
|
||||||
|
|
||||||
if (input.title !== undefined) updateData.title = input.title;
|
if (input.title !== undefined) updateData.title = input.title;
|
||||||
@@ -191,7 +191,7 @@ export function createMeetingsApi(client: SupabaseClient<Database>) {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateItemStatus(input: UpdateItemStatusInput, userId: string) {
|
async updateItemStatus(input: UpdateItemStatusInput, _userId: string) {
|
||||||
const { data, error } = await client
|
const { data, error } = await client
|
||||||
.from('meeting_protocol_items')
|
.from('meeting_protocol_items')
|
||||||
.update({
|
.update({
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface ClubFeeBillingTableProps {
|
|||||||
|
|
||||||
export function ClubFeeBillingTable({
|
export function ClubFeeBillingTable({
|
||||||
billings,
|
billings,
|
||||||
clubId,
|
clubId: _clubId,
|
||||||
}: ClubFeeBillingTableProps) {
|
}: ClubFeeBillingTableProps) {
|
||||||
const [showPaid, setShowPaid] = useState(false);
|
const [showPaid, setShowPaid] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const NOTE_ICONS: Record<string, React.ReactNode> = {
|
|||||||
erinnerung: <Bell className="h-4 w-4" />,
|
erinnerung: <Bell className="h-4 w-4" />,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ClubNotesList({ notes, clubId }: ClubNotesListProps) {
|
export function ClubNotesList({ notes, clubId: _clubId }: ClubNotesListProps) {
|
||||||
const { execute: executeComplete } = useAction(completeClubNote, {
|
const { execute: executeComplete } = useAction(completeClubNote, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success('Aufgabe erledigt');
|
toast.success('Aufgabe erledigt');
|
||||||
|
|||||||
Reference in New Issue
Block a user