Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions migrations/20260612091508_add_bagad_suggestions/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- AlterTable
ALTER TABLE "Adhesion" ALTER COLUMN "photosPaths" DROP DEFAULT;

-- CreateTable
CREATE TABLE "BagadAssoSuggestion" (
"id" SERIAL NOT NULL,
"equipmentName" TEXT NOT NULL,
"equipmentType" TEXT NOT NULL,
"referenceUrl" TEXT,
"associationName" TEXT NOT NULL,
"firstName" TEXT NOT NULL,
"lastName" TEXT NOT NULL,
"position" TEXT NOT NULL,
"contactEmail" TEXT NOT NULL,
"details" TEXT NOT NULL DEFAULT '',
"creationDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"archived" TIMESTAMP(3),

CONSTRAINT "BagadAssoSuggestion_pkey" PRIMARY KEY ("id")
);
6 changes: 6 additions & 0 deletions prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ async function main() {
category: "Bagad'Asso",
description: "Supprimer des tickets"
},
{
name: "edit:bagad-suggestion",
title: "Modifier Suggestion",
category: "Bagad'Asso",
description: "Archiver/désarchiver des suggestions de matériel"
},

// Adhésions
{
Expand Down
15 changes: 15 additions & 0 deletions schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ model BagadAssoTicket {
deleted DateTime?
}

model BagadAssoSuggestion {
id Int @id @default(autoincrement())
equipmentName String
equipmentType String
referenceUrl String?
associationName String
firstName String
lastName String
position String
contactEmail String
details String @default("")
creationDate DateTime @default(now())
archived DateTime?
}

model Adhesion {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
Expand Down
48 changes: 48 additions & 0 deletions src/actions/bagadAsso/archiveSuggestionAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use server"

import { revalidatePath } from "next/cache"

import prisma from "@/helpers/db"
import { hasPermission } from "@/helpers/permissions"
import { getCurrentUserWithPermissions } from "@/helpers/supabase/auth"
import { captureActionError, withServerAction } from "@/lib/sentry"
import { tryCatch } from "@/lib/utils"

type Result = { success: true } | { success: false; error: string }

async function archiveSuggestionActionImpl(
suggestionId: number
): Promise<Result> {
const user = await getCurrentUserWithPermissions()
if (!user) {
return { success: false, error: "Authentification requise" }
}
if (!hasPermission(user, "edit:bagad-suggestion")) {
return {
success: false,
error: "Vous n'avez pas la permission d'effectuer cette opération"
}
}

const result = await tryCatch(
prisma.bagadAssoSuggestion.update({
where: { id: suggestionId },
data: { archived: new Date() }
})
)
if (!result.success) {
captureActionError(result.error)
return {
success: false,
error: "Échec de l'archivage de la suggestion"
}
}

revalidatePath("/dashboard/bagadAsso/suggestions")
return { success: true }
}

export default withServerAction(
"archiveSuggestionAction",
archiveSuggestionActionImpl
)
10 changes: 9 additions & 1 deletion src/actions/bagadAsso/submitBagadAssoFormAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "@/components/public/bagadAsso/form-schema"
import prisma from "@/helpers/db"
import { sendEmail } from "@/helpers/email"
import { locationDisplayName } from "@/helpers/location"
import { captureActionError, withServerAction } from "@/lib/sentry"
import { tryCatch } from "@/lib/utils"

Expand Down Expand Up @@ -95,7 +96,14 @@ async function submitBagadAssoFormActionImpl(
await sendEmail({
to: "evenement@fare-asso.fr",
subject: `Nouveau ticket bagad'Asso #${ticketRecord.id}`,
html: await render(<NewBagadAssoTicket data={ticketRecord} />)
html: await render(
<NewBagadAssoTicket
data={{
...ticketRecord,
eventAddr: locationDisplayName(ticketRecord.eventAddr)
}}
/>
)
})

revalidatePath("/dashboard/bagadAsso")
Expand Down
74 changes: 74 additions & 0 deletions src/actions/bagadAsso/submitSuggestionAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"use server"

import { type } from "arktype"
import { revalidatePath } from "next/cache"
import { isDevelopment } from "std-env"

import { verifyCaptcha } from "@/components/captcha/verify"
import prisma from "@/helpers/db"
import { captureActionError, withServerAction } from "@/lib/sentry"
import { tryCatch } from "@/lib/utils"
import {
BagadAssoSuggestionSchema,
type TBagadAssoSuggestion
} from "@/schemas/bagadAsso"

type Result = { success: true } | { success: false; error: string }

async function submitSuggestionActionImpl(
input: TBagadAssoSuggestion
): Promise<Result> {
const data = BagadAssoSuggestionSchema(input)
if (data instanceof type.errors) {
return {
success: false,
error: "Un ou plusieurs champs sont invalides."
}
}

// Verify CAPTCHA in production
if (!isDevelopment) {
if (!data.captchaToken) {
return { success: false, error: "Veuillez compléter le CAPTCHA." }
}

const isCaptchaValid = await verifyCaptcha(data.captchaToken)
if (!isCaptchaValid) {
return {
success: false,
error: "La vérification CAPTCHA a échoué. Veuillez réessayer."
}
}
}

const created = await tryCatch(
prisma.bagadAssoSuggestion.create({
data: {
equipmentName: data.equipmentName,
equipmentType: data.equipmentType,
referenceUrl: data.referenceUrl || null,
associationName: data.associationName,
firstName: data.firstName,
lastName: data.lastName,
position: data.position,
contactEmail: data.contactEmail,
details: data.details
}
})
)
if (!created.success) {
captureActionError(created.error)
return {
success: false,
error: "Échec de l'envoi de la suggestion. Veuillez réessayer."
}
}

revalidatePath("/dashboard/bagadAsso/suggestions")
return { success: true }
}

export default withServerAction(
"submitSuggestionAction",
submitSuggestionActionImpl
)
48 changes: 48 additions & 0 deletions src/actions/bagadAsso/unarchiveSuggestionAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use server"

import { revalidatePath } from "next/cache"

import prisma from "@/helpers/db"
import { hasPermission } from "@/helpers/permissions"
import { getCurrentUserWithPermissions } from "@/helpers/supabase/auth"
import { captureActionError, withServerAction } from "@/lib/sentry"
import { tryCatch } from "@/lib/utils"

type Result = { success: true } | { success: false; error: string }

async function unarchiveSuggestionActionImpl(
suggestionId: number
): Promise<Result> {
const user = await getCurrentUserWithPermissions()
if (!user) {
return { success: false, error: "Authentification requise" }
}
if (!hasPermission(user, "edit:bagad-suggestion")) {
return {
success: false,
error: "Vous n'avez pas la permission d'effectuer cette opération"
}
}

const result = await tryCatch(
prisma.bagadAssoSuggestion.update({
where: { id: suggestionId },
data: { archived: null }
})
)
if (!result.success) {
captureActionError(result.error)
return {
success: false,
error: "Échec du désarchivage de la suggestion"
}
}

revalidatePath("/dashboard/bagadAsso/suggestions")
return { success: true }
}

export default withServerAction(
"unarchiveSuggestionAction",
unarchiveSuggestionActionImpl
)
27 changes: 27 additions & 0 deletions src/app/(public)/projets/bagad-asso/suggestion/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ArrowLeftIcon } from "lucide-react"
import type { Metadata } from "next"
import Link from "next/link"

import SuggestionForm from "@/components/public/bagadAsso/suggestionForm"

export const metadata: Metadata = {
title: "Suggérer du matériel — Bagad'Asso"
}

export default function BagadAssoSuggestion() {
return (
<div className="flex w-full flex-col items-center justify-start">
<div className="mb-8 w-full max-w-2xl">
<Link
href="/projets/bagad-asso"
className="text-muted-foreground hover:text-foreground inline-flex items-center gap-2 text-sm transition-colors"
>
<ArrowLeftIcon className="h-4 w-4" />
Retour au Bagad'Asso
</Link>
</div>

<SuggestionForm />
</div>
)
}
Loading
Loading