Finish with url copying

This commit is contained in:
Arthur Belleville 2025-09-21 23:09:10 +02:00
parent 27dc530b1c
commit 8d9c7332b3
No known key found for this signature in database
6 changed files with 91 additions and 1 deletions

View file

@ -145,6 +145,7 @@ export type Database = {
deleted_at: string | null
id: string
is_active: boolean
standard_name: string | null
updated_at: string | null
user_id: string
}
@ -154,6 +155,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id: string
}
@ -163,6 +165,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id?: string
}

44
sql/19_standard_name.sql Normal file
View file

@ -0,0 +1,44 @@
-- Add standard_name column to event_types table
-- This column should not be modifiable by authenticated users
-- Add the standard_name column
ALTER TABLE event_types ADD COLUMN standard_name TEXT;
-- Add comment for the new column
COMMENT ON COLUMN event_types.standard_name IS
'Standard name for the event type - not modifiable by authenticated users';
-- Create function to automatically set standard_name on insert and prevent modification by authenticated users
CREATE OR REPLACE FUNCTION handle_event_types_standard_name()
RETURNS TRIGGER AS $$
BEGIN
-- On INSERT: automatically set standard_name from config->>'name', sanitized
IF TG_OP = 'INSERT' THEN
-- Extract name from config and sanitize it (replace spaces with hyphens, lowercase)
NEW.standard_name = LOWER(REPLACE(TRIM(NEW.config->>'name'), ' ', '-'));
RETURN NEW;
END IF;
-- On UPDATE: prevent standard_name modification by authenticated users
IF TG_OP = 'UPDATE' THEN
-- Only allow system/service role to modify standard_name
-- If the current user is authenticated (not service_role), prevent standard_name changes
IF current_setting('role') != 'service_role' AND OLD.standard_name IS DISTINCT FROM NEW.standard_name THEN RAISE EXCEPTION 'standard_name column cannot be modified'; END IF;
-- If name in config changes, update standard_name accordingly (but only for non-authenticated users)
IF current_setting('role') = 'service_role' AND OLD.config->>'name' IS DISTINCT FROM NEW.config->>'name' THEN
NEW.standard_name = LOWER(REPLACE(TRIM(NEW.config->>'name'), ' ', '-'));
END IF;
END IF;
RETURN NEW;
END;
$$ language 'plpgsql';
-- Create trigger to handle standard_name on insert and prevent modification on update
CREATE TRIGGER handle_event_types_standard_name_trigger
BEFORE INSERT OR UPDATE ON event_types
FOR EACH ROW
EXECUTE FUNCTION handle_event_types_standard_name();

View file

@ -20,6 +20,7 @@ export type EventType = {
value: number;
unit: "minutes" | "hours" | "days";
}; // minimum hours in advance
standardName: string;
};
const QUERY_KEY = ["event-types"];
@ -140,6 +141,7 @@ export function useEventTypes() {
...eventTypeConfig,
isActive: eventType.is_active,
id: eventType.id,
standardName: eventType.standard_name,
};
}) ?? []
);

View file

@ -1,12 +1,21 @@
import { useState } from "react";
import { Strong, Text } from "@ui/ui-library/text";
import { Button, ToggleButton } from "@ui/ui-library/button";
import { PlusIcon, EditIcon, TrashIcon, CheckIcon, XIcon } from "lucide-react";
import {
PlusIcon,
EditIcon,
TrashIcon,
CheckIcon,
XIcon,
LinkIcon,
} from "lucide-react";
import { toast } from "@ui/ui-library/toast/toast-queue";
import { EventTypeModal } from "@ui/components/EventTypeModal";
import { EventType, useEventTypes } from "@ui/hooks/event-types";
import { useUser } from "@ui/providers/UserStoreProvider";
export function EventTypesPage() {
const user = useUser();
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingEventType, setEditingEventType] = useState<EventType | null>(
null
@ -71,6 +80,23 @@ export function EventTypesPage() {
setEditingEventType(null);
};
const handleOpenPublicLink = (eventType: EventType) => {
// Sanitize user name for URL (replace spaces with hyphens, lowercase, remove special chars)
const sanitizedUserName = user.name
?.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^a-z0-9-]/g, "");
const shortUserId = user.id.substring(0, 6);
// Construct the public booking URL
const baseUrl = window.location.origin;
const publicUrl = `${baseUrl}/book/${sanitizedUserName}-${shortUserId}/${eventType.standardName}`;
console.log(publicUrl);
// Open in new tab
// window.open(publicUrl, "_blank");
};
return (
<div className="h-full flex flex-col p-4">
<div className="flex justify-between items-start mb-6">
@ -104,6 +130,15 @@ export function EventTypesPage() {
<h3 className="text-lg font-semibold">{eventType.name}</h3>
</div>
<div className="flex gap-2">
<Button
variant="plain"
isIconOnly
onPress={() => handleOpenPublicLink(eventType as EventType)}
className="text-gray-500 hover:text-green-600"
tooltip="Ouvrir le lien de réservation public"
>
<LinkIcon className="w-4 h-4" />
</Button>
<Button
variant="plain"
isIconOnly

View file

@ -145,6 +145,7 @@ export type Database = {
deleted_at: string | null
id: string
is_active: boolean
standard_name: string | null
updated_at: string | null
user_id: string
}
@ -154,6 +155,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id: string
}
@ -163,6 +165,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id?: string
}

View file

@ -145,6 +145,7 @@ export type Database = {
deleted_at: string | null
id: string
is_active: boolean
standard_name: string | null
updated_at: string | null
user_id: string
}
@ -154,6 +155,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id: string
}
@ -163,6 +165,7 @@ export type Database = {
deleted_at?: string | null
id?: string
is_active?: boolean
standard_name?: string | null
updated_at?: string | null
user_id?: string
}