page.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. 'use client';
  2. import { useRouter } from 'next/navigation';
  3. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
  4. import { FileText, Layout, Upload, BookOpen } from 'lucide-react';
  5. import Image from 'next/image';
  6. import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
  7. interface AppTile {
  8. id: string;
  9. title: string;
  10. description: string;
  11. icon: React.ReactNode;
  12. href: string;
  13. color: string;
  14. }
  15. export default function DashboardPage() {
  16. const router = useRouter();
  17. const { isAuthenticated, accessToken } = useKindeBrowserClient();
  18. const roles = accessToken?.roles || [];
  19. const permissions = accessToken?.permissions || [];
  20. // Extract role keys for easier checking
  21. const roleKeys = roles.map(role => role.key);
  22. // Check if user has admin role
  23. const hasAdminRole = isAuthenticated && roleKeys.includes('admin');
  24. // Check if user has customer role and cintas_access permission
  25. const hasCustomerRole = isAuthenticated && roleKeys.includes('customer');
  26. const hasCintasAccess = permissions.includes('cintas_access');
  27. // Check if user can access Cintas summary
  28. const canAccessCintasSummary = hasAdminRole || (hasCustomerRole && hasCintasAccess);
  29. const allApps: AppTile[] = [
  30. {
  31. id: 'files',
  32. title: 'Files',
  33. description: 'Manage and organize your uploaded files',
  34. icon: <FileText className="w-8 h-8" />,
  35. href: '/files',
  36. color: 'bg-blue-500'
  37. },
  38. {
  39. id: 'layout-configurations',
  40. title: 'Layout Configurations',
  41. description: 'Create and manage layout configurations',
  42. icon: <Layout className="w-8 h-8" />,
  43. href: '/layout-configurations',
  44. color: 'bg-green-500'
  45. },
  46. {
  47. id: 'imports',
  48. title: 'Imports',
  49. description: 'Import and manage data from external sources',
  50. icon: <Upload className="w-8 h-8" />,
  51. href: '/imports',
  52. color: 'bg-purple-500'
  53. },
  54. {
  55. id: 'api-docs',
  56. title: 'API Documentation',
  57. description: 'Explore API endpoints and documentation',
  58. icon: <BookOpen className="w-8 h-8" />,
  59. href: '/api-docs',
  60. color: 'bg-orange-500'
  61. },
  62. {
  63. id: 'cintas-calendar-summary',
  64. title: 'Cintas Install Calendar Summary',
  65. description: 'View installation calendar summary and statistics',
  66. icon: (
  67. <div className="w-8 h-8 relative">
  68. <Image
  69. src="/Cintas-Blue.svg"
  70. alt="Cintas"
  71. fill
  72. className="object-contain"
  73. />
  74. </div>
  75. ),
  76. href: '/cintas-calendar-summary',
  77. color: 'bg-blue-600'
  78. }
  79. ];
  80. // Filter apps based on authentication and authorization
  81. const filteredApps = allApps.filter(app => {
  82. // All apps except Cintas require admin role
  83. if (app.id !== 'cintas-calendar-summary') {
  84. return hasAdminRole;
  85. }
  86. // Cintas summary has special access rules
  87. return canAccessCintasSummary;
  88. });
  89. const handleAppClick = (href: string) => {
  90. router.push(href);
  91. };
  92. return (
  93. <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800">
  94. <div className="container mx-auto px-4 py-8">
  95. <div className="text-center mb-12">
  96. <h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4">
  97. Welcome to Vtorio Dashboard
  98. </h1>
  99. <p className="text-lg text-gray-600 dark:text-gray-300">
  100. Select an application to get started
  101. </p>
  102. </div>
  103. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 max-w-6xl mx-auto">
  104. {filteredApps.map((app) => (
  105. <Card
  106. key={app.id}
  107. className="group cursor-pointer transition-all duration-300 hover:shadow-lg hover:scale-105 dark:bg-gray-800 dark:border-gray-700"
  108. onClick={() => handleAppClick(app.href)}
  109. >
  110. <CardHeader className="text-center">
  111. <div className={`${app.id === 'cintas-calendar-summary' ? 'bg-white border-2 border-blue-500' : app.color} w-16 h-16 rounded-full flex items-center justify-center ${app.id === 'cintas-calendar-summary' ? '' : 'text-white'} mx-auto mb-4 group-hover:scale-110 transition-transform duration-300`}>
  112. {app.icon}
  113. </div>
  114. <CardTitle className="text-xl font-semibold text-gray-900 dark:text-white">
  115. {app.title}
  116. </CardTitle>
  117. </CardHeader>
  118. <CardContent>
  119. <CardDescription className="text-center text-gray-600 dark:text-gray-300">
  120. {app.description}
  121. </CardDescription>
  122. </CardContent>
  123. </Card>
  124. ))}
  125. </div>
  126. <div className="mt-12 text-center">
  127. <p className="text-sm text-gray-500 dark:text-gray-400">
  128. Click on any application to access its features
  129. </p>
  130. </div>
  131. </div>
  132. </div>
  133. );
  134. }