Improve email intros

This commit is contained in:
Arthur Belleville 2025-10-18 10:55:49 +02:00
parent 20ac6eddb2
commit 7d78114c29
No known key found for this signature in database
7 changed files with 511 additions and 489 deletions

View file

@ -432,20 +432,20 @@ export type Database = {
}
user_introductions: {
Row: {
config: Json
created_at: string | null
intro_email: string
updated_at: string | null
user_id: string
}
Insert: {
config?: Json
created_at?: string | null
intro_email: string
updated_at?: string | null
user_id: string
}
Update: {
config?: Json
created_at?: string | null
intro_email?: string
updated_at?: string | null
user_id?: string
}

View file

@ -394,16 +394,16 @@ tabloRouter.post("/invite", async (c) => {
);
}
const { data: intro, error: introError } = await supabase
const { data: introConfigData, error: introError } = await supabase
.from("user_introductions")
.select("intro_email")
.select("config")
.eq("user_id", sender.id)
.single();
if (introError) {
return c.json({ error: introError.message }, 500);
}
const introEmail = intro?.intro_email;
const introEmail = introConfigData?.config?.intro_email;
const { error } = await supabase.from("tablo_invites").insert({
invited_email: recipientmail,
@ -428,7 +428,10 @@ tabloRouter.post("/invite", async (c) => {
}/join/${encodeURIComponent(tablo.name)}?token=${encodeURIComponent(
token
)}">ce lien</a> pour accepter l'invitation.</p>
<p>${introEmail}</p>`,
<br>
${introEmail ? `<p>${introEmail}</p>` : ""}
<p>Cordialement.</p>
`,
});
return c.json({

View file

@ -0,0 +1,8 @@
-- Replace intro_email column with config JSONB column
ALTER TABLE user_introductions DROP COLUMN intro_email;
ALTER TABLE user_introductions ADD COLUMN config JSONB NOT NULL DEFAULT '{}'::jsonb;
-- Update column comment
COMMENT ON COLUMN user_introductions.config IS 'User introduction configuration stored as JSON';

View file

@ -6,22 +6,43 @@ import { queryClient } from "src/lib/api";
import { Tables } from "@ui/types/database.types";
import { useEffect, useState } from "react";
export const useIntroduction = () => {
type IntroductionConfig = {
intro_email: string;
};
type Introduction = Tables<"user_introductions"> & {
config: IntroductionConfig;
};
export const useIntroduction = (): {
introduction: IntroductionConfig;
setDraftIntroduction: (cfg: IntroductionConfig) => void;
updateIntroduction: (cfg: IntroductionConfig) => void;
isPending: boolean;
} => {
const { data, isPending } = useFetchIntroduction();
const { mutate: updateIntroduction, isPending: updateIntroductionPending } =
useUpsertIntroduction();
const [draftIntroduction, setDraftIntroduction] =
useState<Tables<"user_introductions"> | null>(data || null);
useState<IntroductionConfig | null>(null);
useEffect(() => {
setDraftIntroduction(data || null);
if (data) {
setDraftIntroduction(data.config as IntroductionConfig);
} else {
setDraftIntroduction({
intro_email: "",
});
}
}, [data]);
return {
introduction: draftIntroduction,
introduction: draftIntroduction ?? {
intro_email: "",
},
setDraftIntroduction,
updateIntroduction,
updateIntroduction: (cfg: IntroductionConfig) =>
updateIntroduction({ introEmail: cfg.intro_email }),
isPending: updateIntroductionPending || isPending,
};
};
@ -32,7 +53,7 @@ export const useIntroduction = () => {
export function useFetchIntroduction() {
const user = useUser();
const { data, isPending } = useQuery<Tables<"user_introductions">>({
const { data, isPending } = useQuery<Introduction>({
queryKey: ["introduction", user.id] as QueryKey,
queryFn: async () => {
const { data, error } = await supabase
@ -65,7 +86,7 @@ export function useUpsertIntroduction() {
const { error } = await supabase.from("user_introductions").upsert(
{
user_id: user.id,
intro_email: introEmail,
config: { intro_email: introEmail },
},
{
onConflict: "user_id",

View file

@ -94,9 +94,7 @@ export default function SettingsPage() {
id="introductionEmail"
value={introduction?.intro_email || ""}
onChange={(e) =>
setDraftIntroduction((prev) =>
prev ? { ...prev, intro_email: e.target.value } : null
)
setDraftIntroduction({ ...introduction, intro_email: e.target.value })
}
placeholder="Bonjour,&#10;&#10;Je vous invite à rejoindre mon espace de travail sur XTablo...&#10;&#10;Cordialement"
rows={8}
@ -110,9 +108,7 @@ export default function SettingsPage() {
<div className="flex justify-end">
<Button
disabled={updateIntroductionPending}
onClick={() =>
updateIntroduction({ introEmail: introduction?.intro_email || "" })
}
onClick={() => updateIntroduction({ intro_email: introduction.intro_email })}
>
{updateIntroductionPending ? "Enregistrement..." : "Enregistrer"}
</Button>

File diff suppressed because it is too large Load diff

View file

@ -432,20 +432,20 @@ export type Database = {
}
user_introductions: {
Row: {
config: Json
created_at: string | null
intro_email: string
updated_at: string | null
user_id: string
}
Insert: {
config?: Json
created_at?: string | null
intro_email: string
updated_at?: string | null
user_id: string
}
Update: {
config?: Json
created_at?: string | null
intro_email?: string
updated_at?: string | null
user_id?: string
}