From a4412c081a584068092d018fce4638e1726865d0 Mon Sep 17 00:00:00 2001 From: alma Date: Fri, 2 May 2025 18:05:28 +0200 Subject: [PATCH] cleaning --- app/[section]/page.tsx | 14 ++-- app/api/auth/[...nextauth]/route.ts | 97 ++++++---------------------- app/artlab/page.tsx | 6 +- app/components/responsive-iframe.tsx | 1 - components/todo.tsx | 37 ----------- hooks/use-email-state.ts | 12 +++- lib/reducers/emailReducer.ts | 25 +++++++ next.config.js | 27 ++++++++ next.config.mjs | 61 ----------------- 9 files changed, 93 insertions(+), 187 deletions(-) delete mode 100644 components/todo.tsx delete mode 100644 next.config.mjs diff --git a/app/[section]/page.tsx b/app/[section]/page.tsx index 45b77a08..380dfc8a 100644 --- a/app/[section]/page.tsx +++ b/app/[section]/page.tsx @@ -15,13 +15,15 @@ const menuItems: Record = { dossiers: process.env.NEXT_PUBLIC_IFRAME_DRIVE_URL || '', 'the-message': process.env.NEXT_PUBLIC_IFRAME_THEMESSAGE_URL || '', qg: process.env.NEXT_PUBLIC_IFRAME_MISSIONVIEW_URL || '', - // Keep any existing custom ones - board: "https://example.com/board", - chapter: "https://example.com/chapter", - flow: "https://example.com/flow", - design: "https://example.com/design", + // Use environment variables for these items too + board: process.env.NEXT_PUBLIC_IFRAME_BOARD_URL || '', + chapter: process.env.NEXT_PUBLIC_IFRAME_CHAPTER_URL || '', + flow: process.env.NEXT_PUBLIC_IFRAME_FLOW_URL || '', + design: process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '', + artlab: process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '', + // External URLs gitlab: "https://gitlab.com", - missions: "https://example.com/missions" + missions: process.env.NEXT_PUBLIC_IFRAME_MISSIONSBOARD_URL || '' } // Using a different approach for metadata that doesn't directly access params.section diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 78a2be0f..7fc5034b 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -82,25 +82,13 @@ export const authOptions: NextAuthOptions = { }, callbacks: { async jwt({ token, account, profile, user }: any) { - // Debug input parameters to understand what's available - console.log('JWT callback - input parameters:', { - hasAccount: !!account, - hasProfile: !!profile, - hasUser: !!user, - hasToken: !!token, - tokenSub: token?.sub, - tokenAccessToken: token?.accessToken ? '[exists]' : undefined - }); - // Initial sign in if (account && account.access_token) { - console.log('JWT callback - NEW SIGN IN with access token detected'); token.accessToken = account.access_token; token.refreshToken = account.refresh_token; // Process the raw profile data if available if (user && user.raw_profile) { - console.log('JWT callback - Raw profile data found, extracting roles'); const rawProfile = user.raw_profile; // Extract roles from all possible sources @@ -108,7 +96,6 @@ export const authOptions: NextAuthOptions = { // Get roles from realm_access if (rawProfile.realm_access && Array.isArray(rawProfile.realm_access.roles)) { - console.log('Found realm_access roles:', rawProfile.realm_access.roles); roles = roles.concat(rawProfile.realm_access.roles); } @@ -118,14 +105,12 @@ export const authOptions: NextAuthOptions = { if (clientId && rawProfile.resource_access[clientId] && Array.isArray(rawProfile.resource_access[clientId].roles)) { - console.log('Found client-specific roles:', rawProfile.resource_access[clientId].roles); roles = roles.concat(rawProfile.resource_access[clientId].roles); } // Also check resource_access roles under 'account' if (rawProfile.resource_access.account && Array.isArray(rawProfile.resource_access.account.roles)) { - console.log('Found account roles:', rawProfile.resource_access.account.roles); roles = roles.concat(rawProfile.resource_access.account.roles); } } @@ -138,18 +123,13 @@ export const authOptions: NextAuthOptions = { // Always ensure user has basic user role const finalRoles = [...new Set([...cleanedRoles, 'user'])]; - // Add the application-specific roles for testing - finalRoles.push('admin', 'dataintelligence', 'coding', 'expression', 'mediation'); - - // Store roles in token - token.role = [...new Set(finalRoles)]; // Ensure uniqueness - console.log('JWT callback - Extracted roles:', token.role); + // Map Keycloak roles to application roles + token.role = mapToApplicationRoles(finalRoles); } else if (user && user.role) { - console.log('JWT callback - Using roles from user object:', user.role); token.role = Array.isArray(user.role) ? user.role : [user.role]; } else { - console.log('JWT callback - No profile data, setting default roles'); - token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation']; + // Default roles if no profile data available + token.role = ['user']; } // Store user information @@ -159,30 +139,14 @@ export const authOptions: NextAuthOptions = { token.last_name = user.last_name || ''; } } - // Token exists but no roles, add default roles for testing + // Token exists but no roles, add default user role else if (token && !token.role) { - console.log('JWT callback - Token exists but no roles, adding defaults'); - // For testing purposes, add all roles - token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation']; + token.role = ['user']; } - // Log the token roles - console.log('JWT token structure:', JSON.stringify({ - sub: token.sub, - role: token.role, - username: token.username - }, null, 2)); - console.log('JWT token roles:', token.role); return token; }, async session({ session, token }: any) { - console.log('Session callback - input parameters:', { - hasSession: !!session, - hasToken: !!token, - tokenRole: token?.role, - tokenSub: token?.sub - }); - // Pass necessary info to the session session.accessToken = token.accessToken; if (session.user) { @@ -194,18 +158,13 @@ export const authOptions: NextAuthOptions = { session.user.username = token.username || ''; session.user.first_name = token.first_name || ''; session.user.last_name = token.last_name || ''; - console.log('Session callback - using token roles:', token.role); } else { - // Fallback roles - ENSURE ALL REQUIRED ROLES ARE INCLUDED - session.user.role = ["user", "admin", "dataintelligence", "coding", "expression", "mediation"]; + // Fallback roles + session.user.role = ["user"]; session.user.username = ''; session.user.first_name = ''; session.user.last_name = ''; - console.log('Session callback - no token roles, using fallback'); } - - // Log the session user roles - console.log('Session user roles:', session.user.role); } return session; } @@ -225,7 +184,7 @@ export const authOptions: NextAuthOptions = { }, }, }, - debug: true, // Enable debug logs to help with troubleshooting + debug: process.env.NODE_ENV === 'development', }; /** @@ -249,40 +208,22 @@ function mapToApplicationRoles(keycloakRoles: string[]): string[] { 'offline_access': ['user'], // Add more mappings as needed }; + + // Map each role and flatten the result + let appRoles: string[] = ['user']; // Always include 'user' role - // Convert all keycloak roles to lowercase for case-insensitive matching - const lowerKeycloakRoles = keycloakRoles.map(role => role.toLowerCase()); - - // Map roles based on the defined mappings - let applicationRoles: string[] = []; - - // Check all Keycloak roles for matches in our mapping - for (const role of lowerKeycloakRoles) { - if (mappings[role]) { - applicationRoles = applicationRoles.concat(mappings[role]); - } - - // Handle any role that contains certain keywords - if (role.includes('admin')) { - applicationRoles.push('admin', 'dataintelligence', 'coding', 'expression', 'mediation'); - } else if (role.includes('developer') || role.includes('dev')) { - applicationRoles.push('coding', 'dataintelligence'); - } else if (role.includes('design')) { - applicationRoles.push('expression'); - } else if (role.includes('data')) { - applicationRoles.push('dataintelligence'); - } else if (role.includes('mediat')) { - applicationRoles.push('mediation'); + for (const role of keycloakRoles) { + const mappedRoles = mappings[role.toLowerCase()]; + if (mappedRoles) { + appRoles = [...appRoles, ...mappedRoles]; } } - // Ensure user always has basic access - applicationRoles.push('user'); - - // Return unique application roles - return [...new Set(applicationRoles)]; + // Remove duplicates and return + return [...new Set(appRoles)]; } const handler = NextAuth(authOptions); + export { handler as GET, handler as POST }; diff --git a/app/artlab/page.tsx b/app/artlab/page.tsx index c6038914..12a934af 100644 --- a/app/artlab/page.tsx +++ b/app/artlab/page.tsx @@ -10,14 +10,14 @@ export default async function ArtlabPage() { redirect("/signin"); } - // Get the direct URL from environment variable - const iframeUrl = process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || ''; + // Get the design URL from environment variable - intentionally shares URL with design section + const designIframeUrl = process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || ''; return (
diff --git a/app/components/responsive-iframe.tsx b/app/components/responsive-iframe.tsx index 936c9e22..00bf7276 100644 --- a/app/components/responsive-iframe.tsx +++ b/app/components/responsive-iframe.tsx @@ -27,7 +27,6 @@ const SERVICE_URLS: Record = { 'the-message': process.env.NEXT_PUBLIC_IFRAME_THEMESSAGE_URL || '', 'qg': process.env.NEXT_PUBLIC_IFRAME_MISSIONVIEW_URL || '', 'design': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '', - 'artlab': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '' }; export default function ResponsiveIframe({ diff --git a/components/todo.tsx b/components/todo.tsx deleted file mode 100644 index 2a3a08ed..00000000 --- a/components/todo.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Checkbox } from "@/components/ui/checkbox"; - -export function Todo() { - const todos = [ - { text: "send e-mails", done: false }, - { text: "do the visuals", done: false }, - { text: "write the contract", done: false }, - ]; - - return ( - - - Todo - - -
- {todos.map((todo, i) => ( -
- - -
- ))} - -
-
-
- ); -} diff --git a/hooks/use-email-state.ts b/hooks/use-email-state.ts index 43a2c97f..bf2c9bff 100644 --- a/hooks/use-email-state.ts +++ b/hooks/use-email-state.ts @@ -473,7 +473,17 @@ export const useEmailState = () => { const newFlaggedStatus = !email.flags.flagged; logEmailOp('TOGGLE_STAR', `Setting starred status to ${newFlaggedStatus} for email ${emailId}`); - // TODO: Implement optimistic update + // Implement optimistic update + dispatch({ + type: 'UPDATE_EMAIL_FLAGS', + payload: { + emailId, + flags: { + flagged: newFlaggedStatus + }, + accountId: email.accountId + } + }); // Make API call const response = await fetch(`/api/courrier/${emailId}/flag`, { diff --git a/lib/reducers/emailReducer.ts b/lib/reducers/emailReducer.ts index b41cb706..7ff67f36 100644 --- a/lib/reducers/emailReducer.ts +++ b/lib/reducers/emailReducer.ts @@ -52,6 +52,7 @@ export type EmailAction = | { type: 'UPDATE_UNREAD_COUNT', payload: { accountId: string, folder: string, count: number } } | { type: 'SET_UNREAD_COUNTS', payload: Record> } | { type: 'TOGGLE_SHOW_FOLDERS', payload: boolean } + | { type: 'UPDATE_EMAIL_FLAGS', payload: { emailId: string, flags: { flagged: boolean }, accountId?: string } } | { type: 'MARK_EMAIL_AS_READ', payload: { emailId: string, isRead: boolean, accountId?: string } }; // Initial state @@ -420,6 +421,30 @@ export function emailReducer(state: EmailState, action: EmailAction): EmailState showFolders: action.payload }; + case 'UPDATE_EMAIL_FLAGS': { + const { emailId, flags, accountId } = action.payload; + + // Update emails list + const updatedEmails = state.emails.map(email => + (email.id === emailId && (!accountId || email.accountId === accountId)) + ? { ...email, flags: { ...email.flags, ...flags } } + : email + ); + + // Update selected email if it matches + const updatedSelectedEmail = state.selectedEmail && + state.selectedEmail.id === emailId && + (!accountId || state.selectedEmail.accountId === accountId) + ? { ...state.selectedEmail, flags: { ...state.selectedEmail.flags, ...flags } } + : state.selectedEmail; + + return { + ...state, + emails: updatedEmails, + selectedEmail: updatedSelectedEmail + }; + } + case 'MARK_EMAIL_AS_READ': { const { emailId, isRead, accountId } = action.payload; diff --git a/next.config.js b/next.config.js index d48bee4a..bbb0dd0a 100644 --- a/next.config.js +++ b/next.config.js @@ -12,6 +12,33 @@ const nextConfig = { } return config; }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + images: { + unoptimized: true, + }, + experimental: { + webpackBuildWorker: true, + parallelServerBuildTraces: true, + parallelServerCompiles: true, + }, + async headers() { + return [ + { + source: '/:path*', + headers: [ + { + key: 'Content-Security-Policy', + value: "frame-ancestors 'self' https://espace.slm-lab.net https://connect.slm-lab.net" + } + ] + } + ] + } }; module.exports = nextConfig; \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs deleted file mode 100644 index 2b4b870d..00000000 --- a/next.config.mjs +++ /dev/null @@ -1,61 +0,0 @@ -let userConfig; -try { - userConfig = await import("./v0-user-next.config"); -} catch (e) { - // ignore error -} - -/** @type {import('next').NextConfig} */ -const nextConfig = { - eslint: { - ignoreDuringBuilds: true, - }, - typescript: { - ignoreBuildErrors: true, - }, - images: { - unoptimized: true, - }, - experimental: { - webpackBuildWorker: true, - parallelServerBuildTraces: true, - parallelServerCompiles: true, - }, - async headers() { - return [ - { - source: '/:path*', - headers: [ - { - key: 'Content-Security-Policy', - value: "frame-ancestors 'self' https://espace.slm-lab.net https://connect.slm-lab.net" - } - ] - } - ] - } -}; - -mergeConfig(nextConfig, userConfig); - -function mergeConfig(nextConfig, userConfig) { - if (!userConfig) { - return; - } - - for (const key in userConfig) { - if ( - typeof nextConfig[key] === "object" && - !Array.isArray(nextConfig[key]) - ) { - nextConfig[key] = { - ...nextConfig[key], - ...userConfig[key], - }; - } else { - nextConfig[key] = userConfig[key]; - } - } -} - -export default nextConfig;