added "members" for an event that help the admins to moderate. members must be invited via email.
This commit is contained in:
@@ -26,7 +26,7 @@ import { ADMIN_EVENTS_PATH } from '../constants';
|
||||
type InviteForm = {
|
||||
email: string;
|
||||
name: string;
|
||||
role: string;
|
||||
role: EventMember['role'];
|
||||
};
|
||||
|
||||
const emptyInvite: InviteForm = {
|
||||
@@ -68,7 +68,6 @@ export default function EventMembersPage() {
|
||||
() => ({
|
||||
tenant_admin: t('management.members.roles.tenantAdmin', 'Tenant-Admin'),
|
||||
member: t('management.members.roles.member', 'Mitglied'),
|
||||
guest: t('management.members.roles.guest', 'Gast'),
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
@@ -275,6 +274,12 @@ export default function EventMembersPage() {
|
||||
<Users className="h-4 w-4 text-emerald-500" />
|
||||
{t('management.members.sections.invite.title', 'Neues Mitglied einladen')}
|
||||
</h3>
|
||||
<p className="text-xs text-slate-500">
|
||||
{t(
|
||||
'management.members.sections.invite.helper',
|
||||
'Mitglieder erhalten Zugriff auf Fotomoderation, Aufgaben und QR-Einladungen. Admins steuern zusätzlich Pakete, Abrechnung und Events.'
|
||||
)}
|
||||
</p>
|
||||
<form className="space-y-3 rounded-2xl border border-emerald-100 bg-white/90 p-4 shadow-sm" onSubmit={handleInvite}>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="invite-email">{t('management.members.form.emailLabel', 'E-Mail')}</Label>
|
||||
@@ -308,7 +313,6 @@ export default function EventMembersPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="tenant_admin">{roleLabels.tenant_admin}</SelectItem>
|
||||
<SelectItem value="member">{roleLabels.member}</SelectItem>
|
||||
<SelectItem value="guest">{roleLabels.guest}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { useAuth } from '../auth/context';
|
||||
import { ADMIN_DEFAULT_AFTER_LOGIN_PATH } from '../constants';
|
||||
import { ADMIN_DEFAULT_AFTER_LOGIN_PATH, ADMIN_EVENTS_PATH } from '../constants';
|
||||
import { encodeReturnTo, resolveReturnTarget } from '../lib/returnTo';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
@@ -48,7 +48,7 @@ type LoginResponse = {
|
||||
}
|
||||
|
||||
export default function LoginPage(): JSX.Element {
|
||||
const { status, applyToken } = useAuth();
|
||||
const { status, applyToken, abilities } = useAuth();
|
||||
const { t } = useTranslation('auth');
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
@@ -56,7 +56,15 @@ export default function LoginPage(): JSX.Element {
|
||||
const searchParams = React.useMemo(() => new URLSearchParams(location.search), [location.search]);
|
||||
const rawReturnTo = searchParams.get('return_to');
|
||||
|
||||
const fallbackTarget = ADMIN_DEFAULT_AFTER_LOGIN_PATH;
|
||||
const computeDefaultAfterLogin = React.useCallback(
|
||||
(abilityList?: string[]) => {
|
||||
const source = abilityList ?? abilities;
|
||||
return source.includes('tenant-admin') ? ADMIN_DEFAULT_AFTER_LOGIN_PATH : ADMIN_EVENTS_PATH;
|
||||
},
|
||||
[abilities],
|
||||
);
|
||||
|
||||
const fallbackTarget = computeDefaultAfterLogin();
|
||||
const { finalTarget } = React.useMemo(
|
||||
() => resolveReturnTarget(rawReturnTo, fallbackTarget),
|
||||
[rawReturnTo, fallbackTarget]
|
||||
@@ -82,7 +90,9 @@ export default function LoginPage(): JSX.Element {
|
||||
onSuccess: async (data) => {
|
||||
setError(null);
|
||||
await applyToken(data.token, data.abilities ?? []);
|
||||
navigate(finalTarget, { replace: true });
|
||||
const postLoginFallback = computeDefaultAfterLogin(data.abilities ?? []);
|
||||
const { finalTarget: successTarget } = resolveReturnTarget(rawReturnTo, postLoginFallback);
|
||||
navigate(successTarget, { replace: true });
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user