ForbiddenView.jsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. "use client";
  2. import React from "react";
  3. import Link from "next/link";
  4. import { useAuth } from "@/components/auth/authContext";
  5. import { branchPath, homePath } from "@/lib/frontend/routes";
  6. import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
  7. import { Button } from "@/components/ui/button";
  8. import {
  9. Card,
  10. CardHeader,
  11. CardTitle,
  12. CardDescription,
  13. CardContent,
  14. CardFooter,
  15. } from "@/components/ui/card";
  16. /**
  17. * ForbiddenView (RHL-021)
  18. *
  19. * Reusable UI block for "authenticated, but not allowed here".
  20. *
  21. * UX rule:
  22. * - All user-facing text must be German.
  23. */
  24. export default function ForbiddenView({ attemptedBranch = null }) {
  25. const { status, user } = useAuth();
  26. const isAuthed = status === "authenticated" && user;
  27. const isBranchUser = isAuthed && user.role === "branch" && user.branchId;
  28. const overviewHref = homePath();
  29. const primaryHref = isBranchUser ? branchPath(user.branchId) : overviewHref;
  30. const primaryLabel = isBranchUser
  31. ? "Zu meiner Niederlassung"
  32. : "Zur Übersicht";
  33. const showSecondaryOverview = isBranchUser;
  34. return (
  35. <Card>
  36. <CardHeader>
  37. <CardTitle>Zugriff verweigert</CardTitle>
  38. <CardDescription>
  39. Sie haben keine Berechtigung, diese Ressource zu öffnen.
  40. </CardDescription>
  41. </CardHeader>
  42. <CardContent className="space-y-4">
  43. <Alert variant="destructive">
  44. <AlertTitle>Keine Berechtigung</AlertTitle>
  45. <AlertDescription>
  46. {attemptedBranch ? (
  47. <span>
  48. Ihr Konto darf die Niederlassung{" "}
  49. <strong>{attemptedBranch}</strong> nicht öffnen.
  50. </span>
  51. ) : (
  52. <span>Ihr Konto darf diese Seite nicht öffnen.</span>
  53. )}
  54. </AlertDescription>
  55. </Alert>
  56. <p className="text-sm text-muted-foreground">
  57. Wenn Sie glauben, dass das ein Fehler ist, wenden Sie sich an Ihren
  58. Administrator.
  59. </p>
  60. </CardContent>
  61. <CardFooter className="flex flex-col gap-2 sm:flex-row sm:justify-end">
  62. {showSecondaryOverview ? (
  63. <Button variant="outline" asChild>
  64. <Link href={overviewHref}>Zur Übersicht</Link>
  65. </Button>
  66. ) : null}
  67. <Button asChild>
  68. <Link href={primaryHref}>{primaryLabel}</Link>
  69. </Button>
  70. </CardFooter>
  71. </Card>
  72. );
  73. }