diff --git a/.drone.yml.back b/.drone.yml.back deleted file mode 100644 index a41ab47..0000000 --- a/.drone.yml.back +++ /dev/null @@ -1,152 +0,0 @@ -kind: pipeline -type: docker -name: default -trigger: - branch: - - master - -steps: -- name: debug-secrets - image: alpine - environment: - VAULT_API_URL: - from_secret: VAULT_API_URL - commands: - - 'echo "Docker Registry URL: $${VAULT_API_URL}"' - when: - event: - - push - - tag - -# Make the image available for next step -- name: publish - image: plugins/docker - settings: - build_args: - - NEXT_PUBLIC_PYTHON_API_URL=https://api.playchoo.com - - NEXT_PUBLIC_AUTH_BACKEND_URL=https://auth.api.playchoo.com - - NEXT_PUBLIC_SWISSOID_TARGET_SERVICE_HANDLE=playchoo - - NEXT_PUBLIC_APP_VERSION=1.0.10 - dockerfile: docker/Dockerfile - context: . - registry: registry.sn48.zivili.ch - repo: registry.sn48.zivili.ch/meow/playchoo-nextjs - tags: - - "amd64-1.0.0" - - "latest" - username: - from_secret: PORTUS_USER - password: - from_secret: PORTUS_PASSWORD - debug: true - launch_debug: true - # make sure to replace image with same tag - force_tag: true - when: - event: - - push - - tag - -- name: deploy - image: registry.sn48.zivili.ch/meow/drone-deploy:amd64-1.0.0 - pull: never - settings: - ssh_port: - from_secret: SSH_PORT - # this is required for the moment to generate the .docker/config.json - # drone is failing to do it on its own at the moment - dockerconfigjson: - from_secret: dockerconfigjson - # use portus or directly docker logins - portus_user: - from_secret: PORTUS_USER - portus_password: - from_secret: PORTUS_PASSWORD - # used by deploy to login to deploy server - ssh_host: - from_secret: SSH_HOST - ssh_user: - from_secret: SSH_USER - ssh_key: - from_secret: SSH_KEY - ssh_fingerprint: - from_secret: SSH_FINGERPRINT - # used by the deploy script to gather all project's .env values from vault - drone_agent1_token: - from_secret: DRONE_AGENT1_TOKEN - # used by deploy script to know where to gather secrets from - vault_api_url: - from_secret: VAULT_API_URL - ---- -kind: secret -name: SSH_HOST -get: - path: kv/data/__drone-admin-secrets - name: SSH_HOST - ---- -kind: secret -name: SSH_USER -get: - path: kv/data/__drone-admin-secrets - name: SSH_USER - ---- -kind: secret -name: SSH_KEY -get: - path: kv/data/__drone-admin-secrets - name: SSH_KEY - ---- -kind: secret -name: DRONE_AGENT1_TOKEN -get: - path: kv/data/__drone-admin-secrets - name: DRONE_AGENT1_TOKEN - ---- -kind: secret -name: VAULT_API_URL -get: - path: kv/data/__drone-admin-secrets - name: VAULT_API_URL - ---- -kind: secret -name: PORTUS_USER -get: - path: kv/data/__drone-admin-secrets - name: PORTUS_USER - ---- -kind: secret -name: PORTUS_PASSWORD -get: - path: kv/data/__drone-admin-secrets - name: PORTUS_PASSWORD - ---- -kind: secret -name: dockerconfigjson -get: - path: kv/data/__drone-admin-secrets - name: dockerconfigjson - -image_pull_secrets: - from_secret: dockerconfigjson - ---- -kind: secret -name: SSH_PORT -get: - path: kv/data/__drone-admin-secrets - name: SSH_PORT - ---- -kind: secret -name: SSH_FINGERPRINT -get: - path: kv/data/__drone-admin-secrets - name: SSH_FINGERPRINT diff --git a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx index d4e3928..b35f8d7 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx @@ -276,7 +276,7 @@ function CourtFormModal({ clubId, court, onClose, onSuccess }: CourtFormModalPro if (nameError) { setFieldError(nameError.message); } - } else if (result.error.code === 'duplicate_court_name') { + } else if (result.error.code === 'court_name_duplicate') { setFieldError(result.error.detail); } else { setError(result.error.detail); @@ -496,11 +496,19 @@ function DependenciesBlockingModal({ court, dependencies, onClose }: Dependencie )} - {dependencies.dependencies.upcoming_bookings > 0 && ( + {dependencies.dependencies.slot_instances_future > 0 && (
- Upcoming bookings: + Future slot instances: - {dependencies.dependencies.upcoming_bookings} + {dependencies.dependencies.slot_instances_future} + +
+ )} + {dependencies.dependencies.slot_instances_booked > 0 && ( +
+ Booked slot instances: + + {dependencies.dependencies.slot_instances_booked}
)} @@ -514,8 +522,11 @@ function DependenciesBlockingModal({ court, dependencies, onClose }: Dependencie {dependencies.dependencies.slot_definitions > 0 && (
  • Delete or reassign all slot definitions
  • )} - {dependencies.dependencies.upcoming_bookings > 0 && ( -
  • Cancel or move all upcoming bookings
  • + {dependencies.dependencies.slot_instances_future > 0 && ( +
  • Delete future slot instances
  • + )} + {dependencies.dependencies.slot_instances_booked > 0 && ( +
  • Cancel or move all booked slot instances
  • )} diff --git a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx index c5b898c..8be2c58 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx @@ -1,7 +1,7 @@ 'use client'; import { useState, useEffect } from 'react'; -import { Loader2, AlertCircle, CheckCircle } from 'lucide-react'; +import { Loader2, AlertCircle, CheckCircle, Info } from 'lucide-react'; import { getClubProfile, updateClubProfile } from '@/src/lib/api/courts'; import type { ClubProfile, ClubProfileUpdateRequest} from '@/src/types/courts'; import { COMMON_TIMEZONES, isValidEmail, isValidUrl } from '@/src/types/courts'; @@ -43,17 +43,17 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps const prof = result.data; setProfile(prof); - // Populate form + // Populate form - read from settings structure setName(prof.name); setTimezone(prof.timezone); - setAddressLine1(prof.address_line_1 || ''); - setAddressLine2(prof.address_line_2 || ''); - setCity(prof.city || ''); - setPostalCode(prof.postal_code || ''); - setCountry(prof.country || ''); - setPhone(prof.phone || ''); - setEmail(prof.email || ''); - setWebsite(prof.website || ''); + setAddressLine1(prof.settings?.address?.line_1 || ''); + setAddressLine2(prof.settings?.address?.line_2 || ''); + setCity(prof.settings?.address?.city || ''); + setPostalCode(prof.settings?.address?.postal_code || ''); + setCountry(prof.settings?.address?.country || ''); + setPhone(prof.settings?.contact?.phone || ''); + setEmail(prof.settings?.contact?.email || ''); + setWebsite(prof.settings?.contact?.website || ''); setError(null); } else { @@ -97,17 +97,29 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps setError(null); setSuccess(false); + // Build settings structure, preserving existing settings + const updatedSettings = { + ...profile?.settings, + address: { + ...profile?.settings?.address, + line_1: addressLine1.trim() || undefined, + line_2: addressLine2.trim() || undefined, + city: city.trim() || undefined, + postal_code: postalCode.trim() || undefined, + country: country.trim() || undefined, + }, + contact: { + ...profile?.settings?.contact, + phone: phone.trim() || undefined, + email: email.trim() || undefined, + website: website.trim() || undefined, + }, + }; + const request: ClubProfileUpdateRequest = { name: name.trim(), timezone, - address_line_1: addressLine1.trim() || undefined, - address_line_2: addressLine2.trim() || undefined, - city: city.trim() || undefined, - postal_code: postalCode.trim() || undefined, - country: country.trim() || undefined, - phone: phone.trim() || undefined, - email: email.trim() || undefined, - website: website.trim() || undefined, + settings: updatedSettings, }; const result = await updateClubProfile(clubId, request); @@ -143,17 +155,17 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps function handleCancel() { if (!profile) return; - // Reset form to original values + // Reset form to original values - read from settings structure setName(profile.name); setTimezone(profile.timezone); - setAddressLine1(profile.address_line_1 || ''); - setAddressLine2(profile.address_line_2 || ''); - setCity(profile.city || ''); - setPostalCode(profile.postal_code || ''); - setCountry(profile.country || ''); - setPhone(profile.phone || ''); - setEmail(profile.email || ''); - setWebsite(profile.website || ''); + setAddressLine1(profile.settings?.address?.line_1 || ''); + setAddressLine2(profile.settings?.address?.line_2 || ''); + setCity(profile.settings?.address?.city || ''); + setPostalCode(profile.settings?.address?.postal_code || ''); + setCountry(profile.settings?.address?.country || ''); + setPhone(profile.settings?.contact?.phone || ''); + setEmail(profile.settings?.contact?.email || ''); + setWebsite(profile.settings?.contact?.website || ''); setErrors({}); setError(null); } @@ -260,7 +272,15 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps {/* Location */}
    -

    Location

    +
    +

    Location

    +
    + +
    + Stored in settings until native fields ship +
    +
    +
    {/* Address Line 1 */} @@ -348,7 +368,15 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps {/* Contact */}
    -

    Contact

    +
    +

    Contact

    +
    + +
    + Stored in settings until native fields ship +
    +
    +
    {/* Phone */} @@ -415,24 +443,6 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps
    - {/* Integration (read-only) */} -
    -

    Integration

    - -
    -
    - Provider: - {profile.provider} -
    - {profile.provider !== 'local' && profile.remote_club_id && ( -
    - Remote Club ID: - {profile.remote_club_id} -
    - )} -
    -
    - {/* Actions */}