ForbiddenView.jsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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. * A reusable UI block for "you are authenticated, but not allowed here".
  20. *
  21. * It relies on AuthContext when available to render the best CTA:
  22. * - branch users -> link to their own branch root
  23. * - admin/dev -> link to home (later: could link to a branch list)
  24. */
  25. export default function ForbiddenView({ attemptedBranch = null }) {
  26. const { status, user } = useAuth();
  27. const isAuthed = status === "authenticated" && user;
  28. const isBranchUser = isAuthed && user.role === "branch" && user.branchId;
  29. const primaryHref = isBranchUser ? branchPath(user.branchId) : homePath();
  30. const primaryLabel = isBranchUser ? "Go to my branch" : "Go to home";
  31. return (
  32. <Card>
  33. <CardHeader>
  34. <CardTitle>Access denied</CardTitle>
  35. <CardDescription>
  36. You are not allowed to access this resource.
  37. </CardDescription>
  38. </CardHeader>
  39. <CardContent className="space-y-4">
  40. <Alert variant="destructive">
  41. <AlertTitle>Forbidden</AlertTitle>
  42. <AlertDescription>
  43. {attemptedBranch ? (
  44. <span>
  45. Your account is not permitted to access branch{" "}
  46. <strong>{attemptedBranch}</strong>.
  47. </span>
  48. ) : (
  49. <span>Your account is not permitted to access this page.</span>
  50. )}
  51. </AlertDescription>
  52. </Alert>
  53. <p className="text-sm text-muted-foreground">
  54. If you believe this is a mistake, please contact your administrator.
  55. </p>
  56. </CardContent>
  57. <CardFooter className="flex flex-col gap-2 sm:flex-row sm:justify-end">
  58. <Button variant="outline" asChild>
  59. <Link href={homePath()}>Home</Link>
  60. </Button>
  61. <Button asChild>
  62. <Link href={primaryHref}>{primaryLabel}</Link>
  63. </Button>
  64. </CardFooter>
  65. </Card>
  66. );
  67. }