From d9280c307825df43f66bad5a27c96923a3c5e263 Mon Sep 17 00:00:00 2001 From: Richard Date: Sat, 1 Aug 2026 12:37:56 +0200 Subject: [PATCH] feat: Allow registered users to sign up guests via new + GAST button --- .../events/__pycache__/views.cpython-314.pyc | Bin 28983 -> 28870 bytes backend/apps/events/views.py | 13 ++-- frontend/dist/index.html | 4 +- frontend/src/App.jsx | 7 ++ frontend/src/components/GuestSignupModal.jsx | 71 ++++++++++-------- frontend/src/components/ShiftMatrixTable.jsx | 49 +++++++----- 6 files changed, 86 insertions(+), 58 deletions(-) diff --git a/backend/apps/events/__pycache__/views.cpython-314.pyc b/backend/apps/events/__pycache__/views.cpython-314.pyc index 4ce723b8833b509cb3e20493f9dae6f33a061121..7451f98afc4137877fa638a5953f7a03638c35c7 100644 GIT binary patch delta 808 zcmX9*T}V?=96#soZqqq+(|uTT>rT^@)QLroO0sY^$D9|H3u3iaJKbG#S3BFyvcRW6 zs)yo0A1}Fwpn^WV4;2yBO9d57A{-;=6Cxsz5~8=xS^tM0=l}ox{-5XmXZZXRtlU^t zX#vzuyiQLT?p2oe!A{-XXE6Krfnhk{o3=^D4UDIj>;j-33_B&G*i4?aJB=>MChj0P z|5{G$B}eSFZg<<-|5Aol(8UkJ(dubC`54;5Np@n3u7h=?Gdd2}=x3umH#ZyW5JHM7 z>`r8|!r_Ff3aW;Mq=pZsgd|c03E_mA$tEVVnkr}72NP;SMmVrDnWjldQDv0HG@=SK z2vdDW(Wqq*ju*{wSwop@d~58xiB1xm6&i#YjY{*L*EId}Z7`2qjL^3d|gx*QBI1;a0E-UXxi?!hG?mfs`i zt=_LrVcFTTpT)zZyW>7%a{GqOnY@;$L*yD833h z#9IC4=nqqQD~I{ge&q7_w~8+IEG^we&g=>FcQZf8K&Gpgm`uh0BhV|942KxgM>R#) zNJ=@B9Z_Ueo0b$b(~(4zD2ueky{9=-53ABg{AnM#9d9v(pfT_#roWHZL%5*--EW8X zt4wi)RSQ!X#XY*`K)J~mW2KE#^#5=xk54haGz^PlQQwu~p{awtV E0J>!96#xJL delta 778 zcmXYtUr19?9LMiDZS%i(ikmWPUS^I>=VmGZ+pF>dt7)Cs=O2((s+!=04#r*HX0unjj zq$Ib7vAmEGcy3C?V_D*6w%>?mE{2hWxbSowPse3Cl}EBT$*bT6lZCt+GyyZ&8~gz6 zda@NG|!HIWXJbv8`f*H%~F<=j~M1QaKmGIjKJTghZ?LK zrTnT9K&n<(-)SrkIW;?NdR2G3YeF4L=kQM*6m7&d_M@zgekOgU*i1}Om$#j| z9aMO=_aq~goqm9oJ2lZmGrelfXJa^yXXG&Eg-kkv(Jf~TC6J8fmDT87sOzSfUb2}m zlb#8i&I`1zFfXi diff --git a/backend/apps/events/views.py b/backend/apps/events/views.py index 7047e4e..5bca0e9 100644 --- a/backend/apps/events/views.py +++ b/backend/apps/events/views.py @@ -341,7 +341,7 @@ class ShiftSignupView(views.APIView): signup = ShiftSignup.objects.create(shift=shift, user=user) return Response({'message': 'Erfolgreich für Schicht eingetragen.', 'signup_id': signup.id}, status=status.HTTP_201_CREATED) - # Guest flow for visitors + # Guest flow for visitors or registered users adding a guest else: if not guest_name: return Response({'error': 'Bitte gib einen Namen an.'}, status=status.HTTP_400_BAD_REQUEST) @@ -350,24 +350,23 @@ class ShiftSignupView(views.APIView): if not is_manager and shift.required_skills.exists(): required_names = ", ".join([s.name for s in shift.required_skills.all()]) return Response({ - 'error': f'Gäste können keine Fähigkeiten haben. Diese Schicht erfordert: {required_names}. Bitte registriere ein Konto mit den passenden Fähigkeiten.' + 'error': f'Gäste können keine Fähigkeiten haben. Diese Schicht erfordert: {required_names}. Ein Gast kann nur durch den Veranstaltungs-Manager/Admin eingetragen werden.' }, status=status.HTTP_400_BAD_REQUEST) if not request.session.session_key: request.session.create() session_key = request.session.session_key - request.session['guest_name'] = guest_name - if ShiftSignup.objects.filter(shift=shift, guest_session_key=session_key).exists(): - return Response({'error': 'Du bist mit deiner Gast-Sitzung bereits für diese Schicht eingetragen.'}, status=status.HTTP_400_BAD_REQUEST) + import uuid + guest_session_key = f"user_{user.id}_guest_{uuid.uuid4().hex[:6]}" if user else session_key signup = ShiftSignup.objects.create( shift=shift, guest_name=guest_name, - guest_session_key=session_key + guest_session_key=guest_session_key ) return Response({ - 'message': f'Gast "{guest_name}" erfolgreich eingetragen!', + 'message': f'Gast "{guest_name}" wurde erfolgreich eingetragen!', 'signup_id': signup.id }, status=status.HTTP_201_CREATED) diff --git a/frontend/dist/index.html b/frontend/dist/index.html index dbb7cdd..f1b6143 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -11,8 +11,8 @@ Schichtplaner — Veranstaltungsschichtpläne - - + +
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 3800596..fd4825c 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -292,6 +292,11 @@ export default function App() { } }; + const handleGuestSignupClick = (shift) => { + setGuestTargetShift(shift); + setShowGuestModal(true); + }; + const handleGuestSubmit = async (guestData) => { if (!guestTargetShift) return; const res = await apiFetch(`/shifts/${guestTargetShift.id}/signup/`, { @@ -600,6 +605,7 @@ export default function App() { event={selectedEventData} user={user} onSignupClick={handleShiftSignupClick} + onGuestSignupClick={handleGuestSignupClick} onCancelClick={handleCancelSignup} onEditEvent={(evt) => { setEventToEdit(evt); @@ -647,6 +653,7 @@ export default function App() { {showGuestModal && ( setShowGuestModal(false)} onSubmit={handleGuestSubmit} /> diff --git a/frontend/src/components/GuestSignupModal.jsx b/frontend/src/components/GuestSignupModal.jsx index 7565096..8d279a2 100644 --- a/frontend/src/components/GuestSignupModal.jsx +++ b/frontend/src/components/GuestSignupModal.jsx @@ -1,31 +1,33 @@ import React, { useState, useEffect } from 'react'; -import { X, UserCheck, AlertCircle } from 'lucide-react'; +import { X, UserPlus, AlertCircle } from 'lucide-react'; -export default function GuestSignupModal({ shift, onClose, onSubmit }) { +export default function GuestSignupModal({ shift, user, onClose, onSubmit }) { const [guestName, setGuestName] = useState(''); const [error, setError] = useState(''); const [submitting, setSubmitting] = useState(false); useEffect(() => { - // Load saved guest name from localStorage - const savedName = localStorage.getItem('guest_display_name') || ''; - if (savedName) { - setGuestName(savedName); + // Only prefill saved guest name for unauthenticated visitors + if (!user) { + const savedName = localStorage.getItem('guest_display_name') || ''; + if (savedName) setGuestName(savedName); } - }, []); + }, [user]); const handleSubmit = async (e) => { e.preventDefault(); setError(''); if (!guestName.trim()) { - setError('Bitte gib deinen Namen ein.'); + setError('Bitte gib den Namen der Person ein.'); return; } - // Save in localStorage for guest convenience - localStorage.setItem('guest_display_name', guestName.trim()); - window.dispatchEvent(new Event('guest_name_updated')); + // Save in localStorage only for unauthenticated guest visitors + if (!user) { + localStorage.setItem('guest_display_name', guestName.trim()); + window.dispatchEvent(new Event('guest_name_updated')); + } setSubmitting(true); try { @@ -39,47 +41,54 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) { }; return ( -
-
+
+
-
-
- +
+
+
-

Als Gast eintragen

-

Schicht: {shift?.title} ({shift?.start_time} - {shift?.end_time})

+

+ {user ? 'Gast in Schicht eintragen' : 'Als Gast eintragen'} +

+

+ Schicht: {shift?.title} ({shift?.start_time} - {shift?.end_time} Uhr) +

{error && ( -
+
{error}
)} -
+
-
@@ -87,16 +96,16 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
diff --git a/frontend/src/components/ShiftMatrixTable.jsx b/frontend/src/components/ShiftMatrixTable.jsx index b79ab58..44dcf23 100644 --- a/frontend/src/components/ShiftMatrixTable.jsx +++ b/frontend/src/components/ShiftMatrixTable.jsx @@ -7,6 +7,7 @@ export default function ShiftMatrixTable({ event, user, onSignupClick, + onGuestSignupClick, onCancelClick, onRemoveUserFromShift, onGenerateClaimLink, @@ -263,24 +264,36 @@ export default function ShiftMatrixTable({ - {isUserSignedUp ? ( - - ) : isFull ? ( - [ VOLL ] - ) : ( - - )} +
+ {isUserSignedUp ? ( + + ) : isFull ? ( + [ VOLL ] + ) : ( + + )} + + {user && !isFull && onGuestSignupClick && ( + + )} +
);