diff --git a/server/src/routes/public.js b/server/src/routes/public.js
index 5bf6c67..978bd61 100644
--- a/server/src/routes/public.js
+++ b/server/src/routes/public.js
@@ -83,10 +83,10 @@ publicRouter.post(
validate(demandeSchema),
async (req, res, next) => {
try {
- const { nom, fonction, entreprise, email } = req.data;
+ const { nom, fonction, entreprise, email, tel } = req.data;
await query(
- 'INSERT INTO demandes_adhesion (nom, fonction, entreprise, email) VALUES ($1, $2, $3, $4)',
- [nom, fonction, entreprise, email]
+ 'INSERT INTO demandes_adhesion (nom, fonction, entreprise, email, tel) VALUES ($1, $2, $3, $4, $5)',
+ [nom, fonction, entreprise, email, tel]
);
res.status(201).json({ ok: true });
} catch (err) {
diff --git a/server/src/schemas.js b/server/src/schemas.js
index ab19f97..3dcdd5c 100644
--- a/server/src/schemas.js
+++ b/server/src/schemas.js
@@ -24,6 +24,7 @@ export const demandeSchema = z.object({
fonction: trimmed(120).optional().default(''),
entreprise: trimmed(120, 1),
email: trimmed(254, 3).email(),
+ tel: trimmed(30, 6),
});
export const inscriptionPublicSchema = z.object({
diff --git a/server/src/sql/schema.sql b/server/src/sql/schema.sql
index 29d4c54..c18624f 100644
--- a/server/src/sql/schema.sql
+++ b/server/src/sql/schema.sql
@@ -135,9 +135,11 @@ CREATE TABLE IF NOT EXISTS demandes_adhesion (
fonction TEXT NOT NULL DEFAULT '' CHECK (char_length(fonction) <= 120),
entreprise TEXT NOT NULL CHECK (char_length(entreprise) BETWEEN 1 AND 120),
email CITEXT NOT NULL CHECK (char_length(email) <= 254),
+ tel TEXT CHECK (char_length(tel) <= 30),
statut TEXT NOT NULL DEFAULT 'nouvelle' CHECK (statut IN ('nouvelle', 'traitee')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
+ALTER TABLE demandes_adhesion ADD COLUMN IF NOT EXISTS tel TEXT CHECK (char_length(tel) <= 30);
CREATE TABLE IF NOT EXISTS site_content (
key TEXT PRIMARY KEY,
diff --git a/web/src/components/AdhesionForm.jsx b/web/src/components/AdhesionForm.jsx
new file mode 100644
index 0000000..ead02d0
--- /dev/null
+++ b/web/src/components/AdhesionForm.jsx
@@ -0,0 +1,88 @@
+import { useState } from 'react';
+import { api } from '../lib/api.js';
+import Modal from './Modal.jsx';
+
+const EMPTY_FORM = { nom: '', fonction: '', entreprise: '', email: '', tel: '' };
+
+export function AdhesionForm({ showTitle = true }) {
+ const [form, setForm] = useState(EMPTY_FORM);
+ const [done, setDone] = useState(false);
+ const [error, setError] = useState('');
+ const [busy, setBusy] = useState(false);
+
+ const onChange = (event) => setForm({ ...form, [event.target.name]: event.target.value });
+ const submit = async (event) => {
+ event.preventDefault();
+ setError('');
+ setBusy(true);
+ try {
+ await api.post('/api/public/demandes-adhesion', form);
+ setDone(true);
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setBusy(false);
+ }
+ };
+
+ if (done) {
+ return (
+
+
✓
+
Demande envoyée !
+
+ Merci pour votre intérêt. Notre équipe vous recontacte sous 48h.
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+export function AdhesionModal({ onClose }) {
+ return (
+
+
+
+
Demande d'adhésion
+
+
+
+ );
+}
diff --git a/web/src/components/Header.jsx b/web/src/components/Header.jsx
index 97351c7..70dfef9 100644
--- a/web/src/components/Header.jsx
+++ b/web/src/components/Header.jsx
@@ -30,7 +30,7 @@ export default function Header() {
Rencontres passées
L'association
Espace membre
-
+
diff --git a/web/src/pages/Home.jsx b/web/src/pages/Home.jsx
index 3b1d169..4424d48 100644
--- a/web/src/pages/Home.jsx
+++ b/web/src/pages/Home.jsx
@@ -5,6 +5,7 @@ import { useAuth } from '../lib/AuthContext.jsx';
import { api, dateParts } from '../lib/api.js';
import Modal from '../components/Modal.jsx';
import PastEventCard from '../components/PastEventCard.jsx';
+import { AdhesionForm, AdhesionModal } from '../components/AdhesionForm.jsx';
export function InscriptionModal({ rencontre, onClose, onDone }) {
const { user, login } = useAuth();
@@ -161,9 +162,7 @@ export default function Home() {
const { data, reload } = usePublicData();
const [searchParams, setSearchParams] = useSearchParams();
const [inscrRenc, setInscrRenc] = useState(null);
- const [homeDone, setHomeDone] = useState(false);
- const [homeError, setHomeError] = useState('');
- const [form, setForm] = useState({ nom: '', fonction: '', entreprise: '', email: '' });
+ const [adhesionOpen, setAdhesionOpen] = useState(false);
// Registration links in invitation emails point to /?inscription= :
// once the public data is loaded, open the matching inscription modal.
@@ -174,21 +173,21 @@ export default function Home() {
if (renc) setInscrRenc(renc);
}, [data, searchParams]);
+ useEffect(() => {
+ if (searchParams.has('adhesion')) setAdhesionOpen(true);
+ }, [searchParams]);
+
const closeInscription = () => {
setInscrRenc(null);
if (searchParams.has('inscription')) setSearchParams({}, { replace: true });
};
- const onChange = (e) => setForm({ ...form, [e.target.name]: e.target.value });
-
- const submitHome = async (e) => {
- e.preventDefault();
- setHomeError('');
- try {
- await api.post('/api/public/demandes-adhesion', form);
- setHomeDone(true);
- } catch (err) {
- setHomeError(err.message);
+ const closeAdhesion = () => {
+ setAdhesionOpen(false);
+ if (searchParams.has('adhesion')) {
+ const next = new URLSearchParams(searchParams);
+ next.delete('adhesion');
+ setSearchParams(next, { replace: true });
}
};
@@ -212,9 +211,7 @@ export default function Home() {
de haut niveau : performance, engagement et esprit collectif.
-
-
-
+
@@ -390,42 +387,7 @@ export default function Home() {
- {homeDone ? (
-
-
✓
-
Demande envoyée !
-
- Merci pour votre intérêt. Notre équipe vous recontacte sous 48h.
-
-
-
- ) : (
-
- )}
+
@@ -433,6 +395,7 @@ export default function Home() {
{inscrRenc && (
)}
+ {adhesionOpen && }
);
}