mirror of
https://github.com/R0m1k3/PleinR.git
synced 2026-10-11 17:27:54 +02:00
Add Plein R email composers
This commit is contained in:
1 parent
28ada88155
commit
b2d428b08b
10 files changed
+584
-1
No files matched your search
@@ -174,7 +174,7 @@ export default async function AssociationPage() {
|
||||
const remaining = Math.max(0, meeting.capacity - registered);
|
||||
const isRegistered = myMeetingIds.has(meeting.id);
|
||||
return (
|
||||
<article key={meeting.id} className="lift" style={{ background: "#fff", border: "1px solid #e6dcc6", borderRadius: 12, overflow: "hidden" }}>
|
||||
<article id={`rencontre-${meeting.id}`} key={meeting.id} className="lift" style={{ background: "#fff", border: "1px solid #e6dcc6", borderRadius: 12, overflow: "hidden", scrollMarginTop: 100 }}>
|
||||
<div style={{ aspectRatio: "16 / 10", background: meeting.imageUrl ? `center/cover no-repeat url(${meeting.imageUrl})` : "repeating-linear-gradient(45deg,#efe9da,#efe9da 12px,#e6ddc9 12px,#e6ddc9 24px)" }} />
|
||||
<div style={{ padding: 18 }}>
|
||||
<div style={{ color: "#9a6638", fontSize: 12.5, fontWeight: 800 }}>
|
||||
|
||||
@@ -16,6 +16,7 @@ const TITLES: Record<string, [string, string]> = {
|
||||
"Validez les offres soumises par les adhérents",
|
||||
],
|
||||
"/backend/rencontres": ["Rencontres", "Gérer les prochaines dates et les archives"],
|
||||
"/backend/emails": ["Création d'e-mails", "Composer des messages aux couleurs de Plein R"],
|
||||
"/backend/administrateurs": ["Administrateurs", "Gérer les accès à l'administration"],
|
||||
"/backend/categories": ["Catégories", "Gérer les métiers de l'annuaire"],
|
||||
"/backend/parametres": ["Paramètres du site", "Configurer l'association et les mentions légales"],
|
||||
@@ -148,6 +149,11 @@ export function BackendShell({
|
||||
{dotRound}Rencontres
|
||||
</NavLink>
|
||||
)}
|
||||
{can(user.role, "manageEmails") && (
|
||||
<NavLink href="/backend/emails" active={pathname === "/backend/emails"}>
|
||||
{dot}E-mails
|
||||
</NavLink>
|
||||
)}
|
||||
{can(user.role, "manageCategories") && (
|
||||
<NavLink href="/backend/categories" active={pathname === "/backend/categories"}>
|
||||
{dotDiamond}Catégories
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/auth";
|
||||
import { EmailCreator } from "@/components/EmailCreator";
|
||||
import { can } from "@/lib/rbac";
|
||||
import { getSiteSettings } from "@/lib/site-settings";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function EmailsPage() {
|
||||
const session = await auth();
|
||||
if (!can(session?.user.role, "manageEmails")) redirect("/backend");
|
||||
const settings = await getSiteSettings();
|
||||
const brand = {
|
||||
associationName: settings.association_name,
|
||||
address: settings.association_address,
|
||||
email: settings.association_email,
|
||||
phone: settings.association_phone,
|
||||
siret: settings.association_siret,
|
||||
};
|
||||
|
||||
return <EmailCreator brand={brand} />;
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import { auth } from "@/auth";
|
||||
import { db } from "@/db";
|
||||
import { meetingRegistrations, meetings, pastMeetingPhotos, pastMeetings } from "@/db/schema";
|
||||
import { ImageField } from "@/components/ImageField";
|
||||
import { MeetingEmailComposer } from "@/components/MeetingEmailComposer";
|
||||
import { can } from "@/lib/rbac";
|
||||
import { getSiteSettings } from "@/lib/site-settings";
|
||||
import {
|
||||
addPastMeetingPhoto,
|
||||
createMeeting,
|
||||
@@ -56,6 +58,14 @@ export default async function RencontresAdminPage() {
|
||||
.select()
|
||||
.from(pastMeetingPhotos)
|
||||
.orderBy(asc(pastMeetingPhotos.position), asc(pastMeetingPhotos.id));
|
||||
const settings = await getSiteSettings();
|
||||
const emailBrand = {
|
||||
associationName: settings.association_name,
|
||||
address: settings.association_address,
|
||||
email: settings.association_email,
|
||||
phone: settings.association_phone,
|
||||
siret: settings.association_siret,
|
||||
};
|
||||
|
||||
const photosByPast = new Map<number, typeof photos>();
|
||||
for (const photo of photos) {
|
||||
@@ -131,6 +141,18 @@ export default async function RencontresAdminPage() {
|
||||
</div>
|
||||
<button type="submit" style={primaryButton}>Enregistrer</button>
|
||||
</form>
|
||||
<MeetingEmailComposer
|
||||
meeting={{
|
||||
id: meeting.id,
|
||||
title: meeting.title,
|
||||
startsAt: meeting.startsAt.toISOString(),
|
||||
location: meeting.location,
|
||||
description: meeting.description,
|
||||
capacity: meeting.capacity,
|
||||
registered: Number(meeting.registered),
|
||||
}}
|
||||
brand={emailBrand}
|
||||
/>
|
||||
<form action={deleteMeeting} style={{ marginTop: 8 }}>
|
||||
<input type="hidden" name="id" value={meeting.id} />
|
||||
<button type="submit" style={dangerButton}>Supprimer</button>
|
||||
|
||||
@@ -456,3 +456,87 @@ img {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* ---- Studio e-mail Plein R ---- */
|
||||
.email-workbench {
|
||||
display: grid;
|
||||
grid-template-columns: 370px minmax(0, 1fr);
|
||||
gap: 26px;
|
||||
align-items: start;
|
||||
}
|
||||
.email-editor-card {
|
||||
background: #fff;
|
||||
border: 1px solid var(--border);
|
||||
border-top: 5px solid var(--gold);
|
||||
border-radius: 16px;
|
||||
padding: 23px;
|
||||
box-shadow: 0 22px 44px -38px rgba(19, 50, 79, 0.75);
|
||||
}
|
||||
.email-editor-kicker {
|
||||
color: var(--brown);
|
||||
font-size: 10.5px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.email-preview-shell {
|
||||
border: 1px solid #d8cdb4;
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
background: #f6f2e8;
|
||||
box-shadow: 0 24px 48px -38px rgba(19, 50, 79, 0.65);
|
||||
}
|
||||
.email-preview-shell iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 760px;
|
||||
border: 0;
|
||||
background: #f6f2e8;
|
||||
}
|
||||
.email-preview-shell.compact iframe {
|
||||
height: 590px;
|
||||
}
|
||||
.email-primary-button,
|
||||
.email-secondary-button,
|
||||
.meeting-email-button {
|
||||
border-radius: 10px;
|
||||
padding: 11px 14px;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
.email-primary-button {
|
||||
border: 1px solid #13324f;
|
||||
background: #13324f;
|
||||
color: #fff;
|
||||
}
|
||||
.email-secondary-button {
|
||||
border: 1px solid #d8cdb4;
|
||||
background: #fff;
|
||||
color: #5a5040;
|
||||
}
|
||||
.email-primary-button:hover { background: #1e588f; }
|
||||
.email-secondary-button:hover { border-color: #9a6638; color: #9a6638; }
|
||||
.email-primary-button:disabled,
|
||||
.email-secondary-button:disabled { opacity: 0.5; cursor: wait; }
|
||||
.meeting-email-button {
|
||||
width: 100%;
|
||||
margin-top: 9px;
|
||||
border: 1px solid #d6b66f;
|
||||
background: #fff8e8;
|
||||
color: #7a5428;
|
||||
}
|
||||
.meeting-email-button:hover { background: #f7e8bf; }
|
||||
.meeting-email-workbench {
|
||||
display: grid;
|
||||
grid-template-columns: 330px minmax(0, 1fr);
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.email-workbench,
|
||||
.meeting-email-workbench { grid-template-columns: 1fr; }
|
||||
.email-preview-shell iframe { height: 620px; }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user