diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f925601 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +Dockerfile +.dockerignore +.idea +assets +node_modules +npm-debug.log +README.md +.next +.git \ No newline at end of file diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index aa9d5fb..d4f69e5 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -48,5 +48,5 @@ jobs: - run: pnpm install - name: Build the application env: - NEXT_PUBLIC_BACKEND_API: "http://localhost:8080" + BACK_END_URL: "http://localhost:8080" run: pnpm build diff --git a/Dockerfile b/Dockerfile index 721e4ce..087e8d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,12 +7,10 @@ RUN apk add --no-cache libc6-compat WORKDIR /app # Install dependencies based on the preferred package manager -COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ +COPY package.json pnpm-lock.yaml* ./ RUN \ - if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ - elif [ -f package-lock.json ]; then npm ci; \ - elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ - else echo "Lockfile not found." && exit 1; \ + if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ + else echo "Pnpm lockfile not found." && exit 1; \ fi diff --git a/README.md b/README.md index fb58947..0c08306 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # FlowInquiry Client [![Build status](https://github.com/flowinquiry/flowinquiry-frontend/actions/workflows/node.js.yml/badge.svg)](https://github.com/flowinquiry/flowinquiry-frontend/actions/workflows/node.js.yml) +![License](https://img.shields.io/badge/License-AGPLv3-blue) ## What is FlowInquiry @@ -11,16 +12,16 @@ FlowInquiry is a service designed to streamline the management of cases, tickets FlowInquiry addresses several challenges faced by organizations in managing cases, tickets, and team communication. Here are some specific use cases: **On-Call System Management** -In an on-call system, teams often face challenges in managing incoming requests or incidents, particularly when multiple shifts or team members are involved. FlowInquiry ensures that each request follows a well-defined workflow, with SLAs for escalation and resolution. This helps reduce response times, avoids missed escalations, and provides clear accountability for handling incidents. +Managing incoming requests or incidents in an on-call system can be challenging with multiple shifts and team members. FlowInquiry streamlines the process by enforcing well-defined workflows with SLAs for escalation and resolution, reducing response times, avoiding missed escalations, and ensuring accountability. **Case Management in CRM Applications** -CRM applications often struggle to manage customer cases effectively, especially when handling inquiries, complaints, or service requests. FlowInquiry enables teams to define custom workflows tailored to specific case types, such as refunds, escalations, or product inquiries. SLAs for each workflow stage ensure customers receive timely updates and resolutions, enhancing customer satisfaction and loyalty. +FlowInquiry helps CRM teams manage customer cases like inquiries, complaints, and service requests by enabling custom workflows tailored to case types such as refunds or escalations. SLAs at each workflow stage ensure timely updates and resolutions, boosting customer satisfaction and loyalty. **Team Communication and Collaboration** -Effective communication within and across teams can be difficult in large organizations, especially when requests involve multiple departments or external stakeholders. FlowInquiry acts as a centralized platform where requests are logged, tracked, and routed through clearly defined workflows. This reduces miscommunication, prevents delays, and ensures all parties are aligned on priorities. +FlowInquiry enhances communication across teams by providing a centralized platform to log, track, and route requests through clear workflows. This minimizes miscommunication, prevents delays, and aligns all stakeholders on priorities, even in large organizations. **Service Request Tracking for IT Teams** -IT teams managing internal service requests often encounter bottlenecks due to unclear processes or manual tracking. FlowInquiry allows IT departments to automate workflows for common requests such as software installation, access management, or issue resolution. The system ensures each request is assigned, processed, and resolved within agreed SLAs. +FlowInquiry automates IT service request workflows, such as software installation and access management, reducing bottlenecks caused by manual tracking. It ensures requests are assigned, processed, and resolved efficiently within SLA timelines. By tailoring workflows to these and other scenarios, FlowInquiry empowers teams to streamline operations, meet deadlines, and deliver exceptional service to both internal and external stakeholders. @@ -109,10 +110,10 @@ Set up the application environment variables by running the following script: scripts/init_environments.sh ``` -This script generates environment variables, including NEXT_PUBLIC_BACKEND_API, to establish the communication between the client and server. Example +This script generates environment variables, including BACK_END_URL, to establish the communication between the client and server. Example ``` -NEXT_PUBLIC_API_BASE_URL=http://localhost:8080 +BACK_END_URL=http://localhost:8080 ``` We recommend running the `scripts/all.sh` script, as it streamlines the process by checking your environment settings and performing all necessary configurations, removing the need to execute multiple scripts manually. diff --git a/next.config.mjs b/next.config.mjs index 3e8103c..866b4cc 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,7 +6,7 @@ const nextConfig = { fallback: [ { source: "/api/:path*", - destination: `${process.env.NEXT_PUBLIC_BACKEND_API}/api/:path*`, + destination: `${process.env.BACK_END_URL}/api/:path*`, }, ], }; diff --git a/package.json b/package.json index 3fedb04..ec28c9e 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "nanoid": "^5.0.9", "next": "^15.1.2", "next-auth": "5.0.0-beta.25", + "next-runtime-env": "^3.2.2", "next-themes": "^0.4.4", "nuqs": "^2.2.3", "react": "^19.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f770a3f..cbeb93a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,6 +169,9 @@ importers: next-auth: specifier: 5.0.0-beta.25 version: 5.0.0-beta.25(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + next-runtime-env: + specifier: ^3.2.2 + version: 3.2.2(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) next-themes: specifier: ^0.4.4 version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -4254,6 +4257,15 @@ packages: nodemailer: optional: true + next-runtime-env@3.2.2: + resolution: + { + integrity: sha512-S5S6NxIf3XeaVc9fLBN2L5Jzu+6dLYCXeOaPQa1RzKRYlG2BBayxXOj6A4VsciocyNkJMazW1VAibtbb1/ZjAw==, + } + peerDependencies: + next: ^14 + react: ^18 + next-themes@0.4.4: resolution: { @@ -8373,6 +8385,11 @@ snapshots: next: 15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 + next-runtime-env@3.2.2(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): + dependencies: + next: 15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + next-themes@0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: react: 19.0.0 diff --git a/scripts/init_environments.sh b/scripts/init_environments.sh index 80e479b..c70c92a 100755 --- a/scripts/init_environments.sh +++ b/scripts/init_environments.sh @@ -33,7 +33,7 @@ while true; do done # Append to the .env.local file -echo "NEXT_PUBLIC_BACKEND_API=\"$backend_server\"" >> "$output_file" +echo "NEXT_PUBLIC_BACK_END_URL=\"$backend_server\"" >> "$output_file" # Run npx auth and append its output to .env diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 7211c0c..700bfb7 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,6 +1,6 @@ import LoginForm from "@/components/auth/login-form"; -const LoginPage = () => { +const LoginPage = async () => { return ; }; export default LoginPage; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8df7c36..bbb0cdd 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import "./theme.css"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; +import { PublicEnvScript } from "next-runtime-env"; import { Toaster } from "@/components/ui/toaster"; import { TooltipProvider } from "@/components/ui/tooltip"; @@ -17,18 +18,14 @@ export const metadata: Metadata = { description: "FlowInquiry dashboard", }; -const RootLayout = async ({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) => { +const RootLayout = async ({ children }: { children: React.ReactNode }) => { return ( + + FlowInquiry - Ticket Management - {/* Favicon for modern browsers */} - {/* Fallback favicon for older browsers */} diff --git a/src/app/page.tsx b/src/app/page.tsx index def249f..9ab5d0d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,13 +1,7 @@ -import { redirect } from "next/navigation"; +import { Home } from "@/components/home"; -import { auth } from "@/auth"; +const Page = async () => { + return ; +}; -export default async function Home() { - const session = await auth(); - if (!session) { - console.warn("No authentication. Redirect to the login page ..."); - redirect("/login"); - } else { - redirect("/portal"); - } -} +export default Page; diff --git a/src/auth.ts b/src/auth.ts index 1b90442..b5d2b91 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -3,6 +3,7 @@ import NextAuth, { User } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import apiAuthSignIn from "@/lib/auth"; +import { BASE_URL } from "@/lib/constants"; export const { handlers, auth } = NextAuth({ providers: [ @@ -18,12 +19,24 @@ export const { handlers, auth } = NextAuth({ if (!credentials) { throw new Error("Invalid credentials"); } - const user = await apiAuthSignIn(credentials); - return user; + return await apiAuthSignIn(credentials); }, }), ], callbacks: { + async redirect({ url, baseUrl }) { + // Allows relative callback URLs + if (url.startsWith("/")) return `${baseUrl}${url}`; + // Works for the deployment model while API_URL is the front url of the reverse proxy + else if ( + process.env.NODE_ENV === "production" && + new URL(url).origin === BASE_URL + ) + return url; + // Allows callback URLs on the same origin + else if (new URL(url).origin === baseUrl) return url; + return baseUrl; + }, jwt({ token, account, user }) { if (user) { token.accessToken = user?.accessToken; diff --git a/src/components/admin-panel/content-layout.tsx b/src/components/admin-panel/content-layout.tsx index 4a93cf7..64408aa 100644 --- a/src/components/admin-panel/content-layout.tsx +++ b/src/components/admin-panel/content-layout.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Navbar } from "@/components/admin-panel/navbar"; interface ContentLayoutProps { diff --git a/src/components/admin-panel/user-nav.tsx b/src/components/admin-panel/user-nav.tsx index 3ecfe60..334008b 100644 --- a/src/components/admin-panel/user-nav.tsx +++ b/src/components/admin-panel/user-nav.tsx @@ -30,6 +30,7 @@ import { TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; +import { BASE_URL } from "@/lib/constants"; export function UserNav() { const { data: session } = useSession(); @@ -49,7 +50,7 @@ export function UserNav() { signOut()} + onClick={() => signOut({ redirectTo: BASE_URL, redirect: true })} > Sign out @@ -110,12 +111,10 @@ export function UserNav() { - {/* Logo */}
- +
- {/* Title and Description */}
FlowInquiry @@ -128,6 +127,24 @@ export function UserNav() {
+ + {/* Footer */} +
+ {/* Copyright and Year */} +
+ © {new Date().getFullYear()} FlowInquiry. All rights reserved. +
+ + {/* Website Link */} + + flowinquiry.io + +
); diff --git a/src/components/app-logo.tsx b/src/components/app-logo.tsx index 83f0beb..13b7972 100644 --- a/src/components/app-logo.tsx +++ b/src/components/app-logo.tsx @@ -1,37 +1,38 @@ import React from "react"; -type IconProps = React.HTMLAttributes; +type IconProps = React.HTMLAttributes & { + size?: number; +}; -const AppLogo = (props: IconProps) => { +const AppLogo = ({ size = 40, ...props }: IconProps) => { return ( - <> - - - - - - - + + + + + + ); }; diff --git a/src/components/auth/login-form.tsx b/src/components/auth/login-form.tsx index d181b33..cabcea6 100644 --- a/src/components/auth/login-form.tsx +++ b/src/components/auth/login-form.tsx @@ -8,6 +8,7 @@ import { useState } from "react"; import { useForm } from "react-hook-form"; import * as z from "zod"; +import AppLogo from "@/components/app-logo"; import { Button } from "@/components/ui/button"; import { Card, @@ -53,7 +54,6 @@ const LoginForm = () => { const response = await signIn("credentials", { email: data.email, password: data.password, - redirectTo: "/portal", redirect: false, }); @@ -65,92 +65,102 @@ const LoginForm = () => { }; return ( - - - Login - - Log into your account with your credentials - - - - {/* Show error message */} - {errorMessage && ( -
- {errorMessage} -
- )} -
- - ( - - - Email - - - - - - )} - > - ( - - - Password - - - - - - - )} - /> -
+
+ {/* App Logo */} +
+ +

+ Empowering Teams with Tailored Workflows +

+
+ + + + Login + + Log into your account with your credentials + + + + {/* Show error message */} + {errorMessage && ( +
+ {errorMessage} +
+ )} + + ( - + + + Email + - -
- Remember me -
+
+ )} + >
+ ( + + + Password + + + + + )} /> - -
- - - - - +
+ ( + + + + +
+ Remember me +
+
+ )} + /> + +
+ + + + + +
); }; diff --git a/src/components/forms/profile-form.tsx b/src/components/forms/profile-form.tsx index 22fee86..17948a4 100644 --- a/src/components/forms/profile-form.tsx +++ b/src/components/forms/profile-form.tsx @@ -35,9 +35,12 @@ import { Separator } from "@/components/ui/separator"; import DefaultUserLogo from "@/components/users/user-logo"; import { useImageCropper } from "@/hooks/use-image-cropper"; import { useToast } from "@/hooks/use-toast"; -import { put } from "@/lib/actions/commons.action"; -import { changePassword, findUserById } from "@/lib/actions/users.action"; -import { BACKEND_API } from "@/lib/constants"; +import { + changePassword, + findUserById, + updateUser, +} from "@/lib/actions/users.action"; +import { BASE_URL } from "@/lib/constants"; import { useError } from "@/providers/error-provider"; import { UserDTOSchema } from "@/types/users"; @@ -89,7 +92,7 @@ export const ProfileForm = () => { formData.append("file", selectedFile); } - await put(`${BACKEND_API}/api/users`, formData, setError); + await updateUser(formData, setError); toast({ description: "Save profile successfully" }); }; @@ -156,7 +159,7 @@ export const ProfileForm = () => { { + const session = getSession(); + if (!session) { + redirect("/login"); + } else { + redirect("/portal"); + } +}; diff --git a/src/components/shared/avatar-display.tsx b/src/components/shared/avatar-display.tsx index d51fff8..f322ab7 100644 --- a/src/components/shared/avatar-display.tsx +++ b/src/components/shared/avatar-display.tsx @@ -5,6 +5,7 @@ import React from "react"; import DefaultTeamLogo from "@/components/teams/team-logo"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import DefaultUserLogo from "@/components/users/user-logo"; +import { BASE_URL } from "@/lib/constants"; interface AvatarDisplayProps { imageUrl?: string | null; @@ -23,7 +24,9 @@ export const AvatarDisplay: React.FC = ({ }) => { return ( - + {fallbackContent} ); diff --git a/src/components/shared/user-select.tsx b/src/components/shared/user-select.tsx index c0d4636..76ed275 100644 --- a/src/components/shared/user-select.tsx +++ b/src/components/shared/user-select.tsx @@ -93,8 +93,6 @@ export const UserSelectField = ({ avatarUrl: user.imageUrl ?? undefined, })); setUsers(filterUsers); - } catch (error) { - console.error("Failed to fetch users:", error); } finally { setIsLoading(false); } diff --git a/src/components/teams/team-form.tsx b/src/components/teams/team-form.tsx index cda0846..af87715 100644 --- a/src/components/teams/team-form.tsx +++ b/src/components/teams/team-form.tsx @@ -26,9 +26,12 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; import { useImageCropper } from "@/hooks/use-image-cropper"; -import { post, put } from "@/lib/actions/commons.action"; -import { findTeamById } from "@/lib/actions/teams.action"; -import { BACKEND_API } from "@/lib/constants"; +import { + createTeam, + findTeamById, + updateTeam, +} from "@/lib/actions/teams.action"; +import { BASE_URL } from "@/lib/constants"; import { obfuscate } from "@/lib/endecode"; import { validateForm } from "@/lib/validator"; import { useError } from "@/providers/error-provider"; @@ -104,13 +107,12 @@ export const TeamForm = ({ teamId }: { teamId: number | undefined }) => { if (formValues.id) { // Edit mode redirectTeamId = formValues.id; - await put(`${BACKEND_API}/api/teams`, formData); + await updateTeam(formData, setError); } else { // Create mode - await post( - `${BACKEND_API}/api/teams`, - formData, - ).then((data) => (redirectTeamId = data.id)); + await createTeam(formData, setError).then( + (data) => (redirectTeamId = data.id), + ); } router.push(`/portal/teams/${obfuscate(redirectTeamId)}/dashboard`); @@ -172,7 +174,9 @@ export const TeamForm = ({ teamId }: { teamId: number | undefined }) => { diff --git a/src/components/teams/team-list.tsx b/src/components/teams/team-list.tsx index c853fce..a7a71c4 100644 --- a/src/components/teams/team-list.tsx +++ b/src/components/teams/team-list.tsx @@ -38,6 +38,7 @@ import { import { useDebouncedCallback } from "@/hooks/use-debounced-callback"; import { usePagePermission } from "@/hooks/use-page-permission"; import { deleteTeams, searchTeams } from "@/lib/actions/teams.action"; +import { BASE_URL } from "@/lib/constants"; import { obfuscate } from "@/lib/endecode"; import { cn } from "@/lib/utils"; import { useError } from "@/providers/error-provider"; @@ -58,7 +59,7 @@ export const TeamList = () => { const [totalElements, setTotalElements] = useState(0); const [loading, setLoading] = useState(false); const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); - const [filterUserTeamsOnly, setFilterUserTeamsOnly] = useState(true); + const [filterUserTeamsOnly, setFilterUserTeamsOnly] = useState(false); const [isDialogOpen, setDialogOpen] = useState(false); const [selectedTeam, setSelectedTeam] = useState(null); @@ -205,7 +206,7 @@ export const TeamList = () => { { { - try { - const data = - rootUserId === DUMMY_MANAGER_ID + const data = + rootUserId === DUMMY_MANAGER_ID + ? await getOrgChart(setError) + : rootUserId === undefined ? await getOrgChart(setError) - : rootUserId === undefined - ? await getOrgChart(setError) - : await getUserHierarchy(rootUserId, setError); - setRootUser(data); - } catch (error) { - console.error("Failed to load org chart:", error); - } + : await getUserHierarchy(rootUserId, setError); + setRootUser(data); }; loadOrgChart(); diff --git a/src/components/users/org-chart-view.tsx b/src/components/users/org-chart-view.tsx index 87d8f00..b45a447 100644 --- a/src/components/users/org-chart-view.tsx +++ b/src/components/users/org-chart-view.tsx @@ -247,17 +247,13 @@ const OrgChartView = ({ userId }: { userId?: number }) => { useEffect(() => { const loadOrgChart = async () => { - try { - const data = - rootUserId === DUMMY_MANAGER_ID + const data = + rootUserId === DUMMY_MANAGER_ID + ? await getOrgChart(setError) + : rootUserId === undefined ? await getOrgChart(setError) - : rootUserId === undefined - ? await getOrgChart(setError) - : await getUserHierarchy(rootUserId, setError); - setRootUser(data); - } catch (error) { - console.error("Failed to load org chart:", error); - } + : await getUserHierarchy(rootUserId, setError); + setRootUser(data); }; loadOrgChart(); diff --git a/src/components/workflows/workflow-create-from-scratch.tsx b/src/components/workflows/workflow-create-from-scratch.tsx index 457c043..a6597ce 100644 --- a/src/components/workflows/workflow-create-from-scratch.tsx +++ b/src/components/workflows/workflow-create-from-scratch.tsx @@ -34,31 +34,27 @@ const NewWorkflowFromScratch = ({ const { setError } = useError(); const handleSave = async (updatedWorkflow: WorkflowDetailDTO) => { - try { - // Ensure the team ID is correctly assigned to the workflow - const workflowToSave = { - ...updatedWorkflow, - visibility: teamId - ? ("PRIVATE" as "PRIVATE" | "PUBLIC" | "TEAM") - : ("PUBLIC" as "PRIVATE" | "PUBLIC" | "TEAM"), - ownerId: teamId, - }; + // Ensure the team ID is correctly assigned to the workflow + const workflowToSave = { + ...updatedWorkflow, + visibility: teamId + ? ("PRIVATE" as "PRIVATE" | "PUBLIC" | "TEAM") + : ("PUBLIC" as "PRIVATE" | "PUBLIC" | "TEAM"), + ownerId: teamId, + }; - const workflow = await saveWorkflowDetail(workflowToSave, setError); + const workflow = await saveWorkflowDetail(workflowToSave, setError); - if (workflow?.id) { - if (teamId) { - router.push( - `/portal/teams/${obfuscate(teamId)}/workflows/${obfuscate(workflow.id)}`, - ); - } else { - router.push(`/portal/settings/workflows/${obfuscate(workflow.id)}`); - } + if (workflow?.id) { + if (teamId) { + router.push( + `/portal/teams/${obfuscate(teamId)}/workflows/${obfuscate(workflow.id)}`, + ); } else { - console.error("Workflow save failed: Missing workflow ID."); + router.push(`/portal/settings/workflows/${obfuscate(workflow.id)}`); } - } catch (error) { - console.error("Error saving workflow:", error); + } else { + console.error("Workflow save failed: Missing workflow ID."); } }; diff --git a/src/lib/actions/activity-logs.action.ts b/src/lib/actions/activity-logs.action.ts index 1aebac0..70ef556 100644 --- a/src/lib/actions/activity-logs.action.ts +++ b/src/lib/actions/activity-logs.action.ts @@ -1,5 +1,4 @@ import { get } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { ActivityLogDTO } from "@/types/activity-logs"; import { EntityType, PageableResult } from "@/types/commons"; @@ -11,7 +10,7 @@ export const getActivityLogs = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/activity-logs?entityType=${entityType}&entityId=${entityId}&page=${page}&size=${displayNumber}&sort=createdAt,desc`, + `/api/activity-logs?entityType=${entityType}&entityId=${entityId}&page=${page}&size=${displayNumber}&sort=createdAt,desc`, setError, ); }; @@ -23,7 +22,7 @@ export const getUserActivities = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/activity-logs/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, + `/api/activity-logs/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, setError, ); }; diff --git a/src/lib/actions/authorities.action.ts b/src/lib/actions/authorities.action.ts index 35b325e..757cdee 100644 --- a/src/lib/actions/authorities.action.ts +++ b/src/lib/actions/authorities.action.ts @@ -1,5 +1,4 @@ import { deleteExec, get, post } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { AuthorityDTO, AuthorityResourcePermissionDTO, @@ -13,7 +12,7 @@ export const getAuthorities = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/authorities?page=${page}&size=2000&sort=descriptiveName,asc`, + `/api/authorities?page=${page}&size=2000&sort=descriptiveName,asc`, setError, ); }; @@ -22,7 +21,7 @@ export const findAuthorityByName = async ( name: string, setError?: (error: string | null) => void, ) => { - return get(`${BACKEND_API}/api/authorities/${name}`, setError); + return get(`/api/authorities/${name}`, setError); }; export const createAuthority = async ( @@ -30,7 +29,7 @@ export const createAuthority = async ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/authorities`, + `/api/authorities`, authority, setError, ); @@ -41,7 +40,7 @@ export const deleteAuthority = async ( setError?: (error: string | null) => void, ) => { return deleteExec( - `${BACKEND_API}/api/authorities/${authority_name}`, + `/api/authorities/${authority_name}`, undefined, setError, ); @@ -52,7 +51,7 @@ export const findPermissionsByAuthorityName = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/authority-permissions/${authorityName}`, + `/api/authority-permissions/${authorityName}`, setError, ); }; @@ -64,11 +63,7 @@ export const batchSavePermissions = async ( return post< Array, Array - >( - `${BACKEND_API}/api/authority-permissions/batchSave`, - permissions, - setError, - ); + >(`/api/authority-permissions/batchSave`, permissions, setError); }; export async function getUsersByAuthority( @@ -77,7 +72,7 @@ export async function getUsersByAuthority( ) { const queryParams = createQueryParams(pagination); return get>( - `${BACKEND_API}/api/authorities/${authority}/users?${queryParams.toString()}`, + `/api/authorities/${authority}/users?${queryParams.toString()}`, ); } @@ -86,7 +81,7 @@ export async function findUsersNotInAuthority( authorityName: string, ) { return get>( - `${BACKEND_API}/api/authorities/searchUsersNotInAuthority?userTerm=${userTerm}&&authorityName=${authorityName}`, + `/api/authorities/searchUsersNotInAuthority?userTerm=${userTerm}&&authorityName=${authorityName}`, ); } @@ -94,17 +89,12 @@ export const addUsersToAuthority = ( authorityName: string, userIds: number[], ) => { - return post( - `${BACKEND_API}/api/authorities/${authorityName}/add-users`, - userIds, - ); + return post(`/api/authorities/${authorityName}/add-users`, userIds); }; export const deleteUserFromAuthority = async ( authorityName: string, userId: number, ) => { - return deleteExec( - `${BACKEND_API}/api/authorities/${authorityName}/users/${userId}`, - ); + return deleteExec(`/api/authorities/${authorityName}/users/${userId}`); }; diff --git a/src/lib/actions/comments.action.ts b/src/lib/actions/comments.action.ts index 78a127a..491aadb 100644 --- a/src/lib/actions/comments.action.ts +++ b/src/lib/actions/comments.action.ts @@ -1,5 +1,4 @@ import { get, post } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { CommentDTO, EntityType } from "@/types/commons"; export const getCommentsForEntity = ( @@ -8,7 +7,7 @@ export const getCommentsForEntity = ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/comments?entityType=${entityType}&&entityId=${entityId}`, + `/api/comments?entityType=${entityType}&&entityId=${entityId}`, setError, ); }; @@ -17,9 +16,5 @@ export const createNewComment = async ( comment: CommentDTO, setError?: (error: string | null) => void, ) => { - return post( - `${BACKEND_API}/api/comments`, - comment, - setError, - ); + return post(`/api/comments`, comment, setError); }; diff --git a/src/lib/actions/commons.action.ts b/src/lib/actions/commons.action.ts index 55cb2c9..2921391 100644 --- a/src/lib/actions/commons.action.ts +++ b/src/lib/actions/commons.action.ts @@ -1,5 +1,6 @@ import { auth } from "@/auth"; import { getAccessToken } from "@/lib/access-token-manager"; +import { BACK_END_URL, BASE_URL } from "@/lib/constants"; import { handleError, HttpError } from "@/lib/errors"; import { PageableResult } from "@/types/commons"; import { @@ -42,7 +43,9 @@ export const fetchData = async ( } try { - const response = await fetch(url, options); + const apiUrl = + securityMode === SecurityMode.CLIENT_SECURE ? BASE_URL : BACK_END_URL; + const response = await fetch(`${apiUrl}${url}`, options); if (response.ok) { const contentType = response.headers.get("content-type"); diff --git a/src/lib/actions/notifications.action.ts b/src/lib/actions/notifications.action.ts index c117c34..405fe35 100644 --- a/src/lib/actions/notifications.action.ts +++ b/src/lib/actions/notifications.action.ts @@ -1,5 +1,4 @@ import { get, post } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { NotificationDTO, PageableResult } from "@/types/commons"; export async function getUnReadNotificationsByUserId( @@ -7,7 +6,7 @@ export async function getUnReadNotificationsByUserId( setError?: (error: string | null) => void, ) { return get>( - `${BACKEND_API}/api/notifications/unread?userId=${userId}`, + `/api/notifications/unread?userId=${userId}`, setError, ); } @@ -16,7 +15,7 @@ export async function markNotificationsAsRead( notificationIds: number[], setError?: (error: string | null) => void, ): Promise { - return post(`${BACKEND_API}/api/notifications/mark-read`, { + return post(`/api/notifications/mark-read`, { notificationIds: notificationIds, setError, }); @@ -29,7 +28,7 @@ export async function getUserNotifications( setError?: (error: string | null) => void, ) { return get>( - `${BACKEND_API}/api/notifications/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, + `/api/notifications/user/${userId}?page=${page}&size=${displayNumber}&sort=createdAt,desc`, setError, ); } diff --git a/src/lib/actions/shared.action.ts b/src/lib/actions/shared.action.ts index eb384e0..2d9755a 100644 --- a/src/lib/actions/shared.action.ts +++ b/src/lib/actions/shared.action.ts @@ -1,5 +1,4 @@ import { get } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { mapEntityToFilterOptions } from "@/lib/mappers"; import { EntityValueDefinition } from "@/types/commons"; @@ -9,7 +8,7 @@ export interface TimezoneInfo { } export const getTimezones = async (): Promise> => { - return get>(`${BACKEND_API}/api/timezones`); + return get>(`/api/timezones`); }; export const findEntitiesFilterOptions = async ( diff --git a/src/lib/actions/teams-request.action.ts b/src/lib/actions/teams-request.action.ts index 244943f..1e39983 100644 --- a/src/lib/actions/teams-request.action.ts +++ b/src/lib/actions/teams-request.action.ts @@ -1,7 +1,4 @@ -import { unstable_noStore as noStore } from "next/dist/server/web/spec-extension/unstable-no-store"; - import { doAdvanceSearch, get, post, put } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { PageableResult } from "@/types/commons"; import { Pagination, QueryDTO } from "@/types/query"; import { @@ -20,7 +17,7 @@ export const createTeamRequest = async ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/team-requests`, + `/api/team-requests`, teamRequest, setError, ); @@ -30,10 +27,7 @@ export const findRequestById = async ( requestId: number, setError?: (error: string | null) => void, ) => { - return get( - `${BACKEND_API}/api/team-requests/${requestId}`, - setError, - ); + return get(`/api/team-requests/${requestId}`, setError); }; export const updateTeamRequest = async ( @@ -42,7 +36,7 @@ export const updateTeamRequest = async ( setError?: (error: string | null) => void, ) => { return put( - `${BACKEND_API}/api/team-requests/${teamRequestId}`, + `/api/team-requests/${teamRequestId}`, teamRequest, setError, ); @@ -53,9 +47,8 @@ export async function searchTeamRequests( pagination: Pagination, setError?: (error: string | null) => void, ) { - noStore(); return doAdvanceSearch( - `${BACKEND_API}/api/team-requests/search`, + `/api/team-requests/search`, query, pagination, setError, @@ -67,7 +60,7 @@ export const findPreviousTeamRequest = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/${requestId}/previous`, + `/api/team-requests/${requestId}/previous`, setError, ); }; @@ -76,10 +69,7 @@ export const findNextTeamRequest = async ( requestId: number, setError?: (error: string | null) => void, ) => { - return get( - `${BACKEND_API}/api/team-requests/${requestId}/next`, - setError, - ); + return get(`/api/team-requests/${requestId}/next`, setError); }; export const getTicketsAssignmentDistributionByTeam = async ( @@ -87,7 +77,7 @@ export const getTicketsAssignmentDistributionByTeam = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/teams/${teamId}/ticket-distribution`, + `/api/team-requests/teams/${teamId}/ticket-distribution`, setError, ); }; @@ -97,7 +87,7 @@ export const getTicketsPriorityDistributionByTeam = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/teams/${teamId}/priority-distribution`, + `/api/team-requests/teams/${teamId}/priority-distribution`, setError, ); }; @@ -110,7 +100,7 @@ export const getUnassignedTickets = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/team-requests/teams/${teamId}/unassigned-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + `/api/team-requests/teams/${teamId}/unassigned-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, setError, ); }; @@ -123,7 +113,7 @@ export const getOverdueTicketsByTeam = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/team-requests/teams/${teamId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + `/api/team-requests/teams/${teamId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, setError, ); }; @@ -133,7 +123,7 @@ export const getTicketStatisticsByTeamId = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/teams/${teamId}/statistics`, + `/api/team-requests/teams/${teamId}/statistics`, setError, ); }; @@ -143,7 +133,7 @@ export const getCountOverdueTicketsByTeamId = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/teams/${teamId}/overdue-tickets/count`, + `/api/team-requests/teams/${teamId}/overdue-tickets/count`, setError, ); }; @@ -154,7 +144,7 @@ export const getTicketCreationDaySeries = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/teams/${teamId}/ticket-creations-day-series?days=${days}`, + `/api/team-requests/teams/${teamId}/ticket-creations-day-series?days=${days}`, setError, ); }; @@ -167,7 +157,7 @@ export const getOverdueTicketsByUser = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/team-requests/users/${userId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, + `/api/team-requests/users/${userId}/overdue-tickets?page=${page}&size=5&sort=${sortBy},${sortDirection}`, setError, ); }; @@ -177,7 +167,7 @@ export const getTeamTicketPriorityDistributionForUser = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/team-requests/users/${userId}/team-tickets-priority-distribution`, + `/api/team-requests/users/${userId}/team-tickets-priority-distribution`, setError, ); }; diff --git a/src/lib/actions/teams.action.ts b/src/lib/actions/teams.action.ts index c8c527c..c96d8ef 100644 --- a/src/lib/actions/teams.action.ts +++ b/src/lib/actions/teams.action.ts @@ -3,17 +3,31 @@ import { doAdvanceSearch, get, post, + put, } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { Pagination, QueryDTO } from "@/types/query"; import { TeamDTO, TransitionItemCollectionDTO } from "@/types/teams"; import { UserDTO, UserWithTeamRoleDTO } from "@/types/users"; +export const createTeam = async ( + teamForm: FormData, + setError?: (error: string | null) => void, +) => { + return post(`/api/teams`, teamForm, setError); +}; + +export const updateTeam = async ( + teamForm: FormData, + setError?: (error: string | null) => void, +) => { + return put(`/api/teams`, teamForm, setError); +}; + export const findTeamById = async ( teamId: number, setError?: (error: string | null) => void, ) => { - return get(`${BACKEND_API}/api/teams/${teamId}`, setError); + return get(`/api/teams/${teamId}`, setError); }; export async function searchTeams( @@ -22,7 +36,7 @@ export async function searchTeams( setError?: (error: string | null) => void, ) { return doAdvanceSearch( - `${BACKEND_API}/api/teams/search`, + `/api/teams/search`, query, pagination, setError, @@ -33,7 +47,7 @@ export async function deleteTeams( ids: number[], setError?: (error: string | null) => void, ) { - return deleteExec(`${BACKEND_API}/api/teams`, ids, setError); + return deleteExec(`/api/teams`, ids, setError); } export async function findMembersByTeamId( @@ -41,7 +55,7 @@ export async function findMembersByTeamId( setError?: (error: string | null) => void, ) { return get>( - `${BACKEND_API}/api/teams/${teamId}/members`, + `/api/teams/${teamId}/members`, setError, ); } @@ -50,10 +64,7 @@ export async function findTeamsByMemberId( userId: number, setError?: (error: string | null) => void, ) { - return get>( - `${BACKEND_API}/api/teams/users/${userId}`, - setError, - ); + return get>(`/api/teams/users/${userId}`, setError); } export async function findUsersNotInTeam( @@ -62,7 +73,7 @@ export async function findUsersNotInTeam( setError?: (error: string | null) => void, ) { return get>( - `${BACKEND_API}/api/teams/searchUsersNotInTeam?userTerm=${userTerm}&&teamId=${teamId}`, + `/api/teams/searchUsersNotInTeam?userTerm=${userTerm}&&teamId=${teamId}`, setError, ); } @@ -74,7 +85,7 @@ export const addUsersToTeam = ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/teams/${teamId}/add-users`, + `/api/teams/${teamId}/add-users`, { userIds: userIds, role: teamRole, @@ -89,7 +100,7 @@ export const deleteUserFromTeam = async ( setError?: (error: string | null) => void, ) => { return deleteExec( - `${BACKEND_API}/api/teams/${teamId}/users/${userId}`, + `/api/teams/${teamId}/users/${userId}`, undefined, setError, ); @@ -101,7 +112,7 @@ export const getUserRoleInTeam = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/teams/${teamId}/users/${userId}/role`, + `/api/teams/${teamId}/users/${userId}/role`, setError, ); }; @@ -111,7 +122,7 @@ export const getTeamRequestStateChangesHistory = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/team-requests/${ticketId}/states-history`, + `/api/team-requests/${ticketId}/states-history`, setError, ); }; diff --git a/src/lib/actions/users.action.ts b/src/lib/actions/users.action.ts index 6234123..7390f32 100644 --- a/src/lib/actions/users.action.ts +++ b/src/lib/actions/users.action.ts @@ -8,7 +8,7 @@ import { put, SecurityMode, } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; +import { Permission } from "@/providers/permissions-provider"; import { Pagination, QueryDTO } from "@/types/query"; import { UserDTO, UserHierarchyDTO } from "@/types/users"; @@ -19,62 +19,60 @@ export async function searchUsers( ) { noStore(); return doAdvanceSearch( - `${BACKEND_API}/api/users/search`, + `/api/users/search`, query, pagination, setError, ); } +export const getUserPermissions = async ( + userId: number, + setError?: (error: string | null) => void, +) => { + return get>(`/api/users/permissions/${userId}`, setError); +}; + export const getDirectReports = async ( userId: number, setError?: (error: string | null) => void, ) => { - return get>( - `${BACKEND_API}/api/users/${userId}/direct-reports`, - setError, - ); + return get>(`/api/users/${userId}/direct-reports`, setError); }; export const findUserById = async ( userId: number, setError?: (error: string | null) => void, ) => { - return get(`${BACKEND_API}/api/users/${userId}`, setError); + return get(`/api/users/${userId}`, setError); }; export const createUser = async ( user: UserDTO, setError?: (error: string | null) => void, ) => { - if (user.id) { - const formData = new FormData(); - const userJsonBlob = new Blob([JSON.stringify(user)], { - type: "application/json", - }); - formData.append("userDTO", userJsonBlob); - return put( - `${BACKEND_API}/api/users`, - formData, - setError, - ); - } else { - return post(`${BACKEND_API}/api/users`, user, setError); - } + return post(`/api/users`, user, setError); +}; + +export const updateUser = async ( + userForm: FormData, + setError?: (error: string | null) => void, +) => { + return put(`/api/users`, userForm, setError); }; export const deleteUser = async ( userId: number, setError?: (error: string | null) => void, ) => { - return deleteExec(`${BACKEND_API}/api/users/${userId}`, setError); + return deleteExec(`/api/users/${userId}`, setError); }; export const resendActivationEmail = async ( email: string, setError?: (error: string | null) => void, ) => { - return get(`${BACKEND_API}/api/${email}/resend-activation-email`, setError); + return get(`/api/${email}/resend-activation-email`, setError); }; export const passwordReset = async ( @@ -83,7 +81,7 @@ export const passwordReset = async ( setError?: (error: string | null) => void, ) => { await post( - `${BACKEND_API}/api/account/reset-password/finish`, + `/api/account/reset-password/finish`, { key: key, newPassword: password }, setError, SecurityMode.NOT_SECURE, @@ -95,7 +93,7 @@ export const forgotPassword = async ( setError?: (error: string | null) => void, ) => { await get( - `${BACKEND_API}/api/account/reset-password/init?email=${email}`, + `/api/account/reset-password/init?email=${email}`, setError, SecurityMode.NOT_SECURE, ); @@ -107,7 +105,7 @@ export const changePassword = async ( setError?: (error: string | null) => void, ) => { await post( - `${BACKEND_API}/api/account/change-password`, + `/api/account/change-password`, { currentPassword: currentPassword, newPassword: newPassword, @@ -119,15 +117,12 @@ export const changePassword = async ( export const getOrgChart = async ( setError?: (error: string | null) => void, ) => { - return get(`${BACKEND_API}/api/users/orgChart`, setError); + return get(`/api/users/orgChart`, setError); }; export const getUserHierarchy = async ( userId: number, setError?: (error: string | null) => void, ) => { - return get( - `${BACKEND_API}/api/users/${userId}/hierarchy`, - setError, - ); + return get(`/api/users/${userId}/hierarchy`, setError); }; diff --git a/src/lib/actions/workflows.action.ts b/src/lib/actions/workflows.action.ts index 9b74fcc..00b3ec1 100644 --- a/src/lib/actions/workflows.action.ts +++ b/src/lib/actions/workflows.action.ts @@ -5,7 +5,6 @@ import { post, put, } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; import { Pagination, QueryDTO } from "@/types/query"; import { WorkflowDetailDTO, @@ -17,10 +16,7 @@ export const getWorkflowsByTeam = ( teamId: number, setError?: (error: string | null) => void, ) => { - return get>( - `${BACKEND_API}/api/workflows/teams/${teamId}`, - setError, - ); + return get>(`/api/workflows/teams/${teamId}`, setError); }; export const getGlobalWorkflowHasNotLinkedWithTeam = ( @@ -28,7 +24,7 @@ export const getGlobalWorkflowHasNotLinkedWithTeam = ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/workflows/teams/${teamId}/global-workflows-not-linked-yet`, + `/api/workflows/teams/${teamId}/global-workflows-not-linked-yet`, setError, ); }; @@ -40,7 +36,7 @@ export const getValidTargetStates = async ( setError?: (error: string | null) => void, ) => { return get>( - `${BACKEND_API}/api/workflows/${workflowId}/transitions?workflowStateId=${workflowStateId}&&includeSelf=${includeSelf}`, + `/api/workflows/${workflowId}/transitions?workflowStateId=${workflowStateId}&&includeSelf=${includeSelf}`, setError, ); }; @@ -51,7 +47,7 @@ export async function searchWorkflows( setError?: (error: string | null) => void, ) { return doAdvanceSearch( - `${BACKEND_API}/api/workflows/search`, + `/api/workflows/search`, query, pagination, setError, @@ -63,7 +59,7 @@ export const getWorkflowDetail = async ( setError?: (error: string | null) => void, ) => { return get( - `${BACKEND_API}/api/workflows/details/${workflowId}`, + `/api/workflows/details/${workflowId}`, setError, ); }; @@ -73,7 +69,7 @@ export const saveWorkflowDetail = async ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/workflows/details`, + `/api/workflows/details`, workflowDetail, setError, ); @@ -85,7 +81,7 @@ export const updateWorkflowDetail = async ( setError?: (error: string | null) => void, ) => { return put( - `${BACKEND_API}/api/workflows/details/${workflowId}`, + `/api/workflows/details/${workflowId}`, workflowDetail, setError, ); @@ -98,7 +94,7 @@ export const createWorkflowFromReference = async ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/workflows/${referenceWorkflowId}/teams/${teamId}/create-workflow-reference`, + `/api/workflows/${referenceWorkflowId}/teams/${teamId}/create-workflow-reference`, workflowDto, setError, ); @@ -111,7 +107,7 @@ export const createWorkflowFromCloning = async ( setError?: (error: string | null) => void, ) => { return post( - `${BACKEND_API}/api/workflows/${cloneWorkflowId}/teams/${teamId}/create-workflow-clone`, + `/api/workflows/${cloneWorkflowId}/teams/${teamId}/create-workflow-clone`, workflowDto, setError, ); @@ -121,9 +117,5 @@ export const deleteWorkflow = async ( workflowId: number, setError?: (error: string | null) => void, ) => { - return deleteExec( - `${BACKEND_API}/api/workflows/${workflowId}`, - undefined, - setError, - ); + return deleteExec(`/api/workflows/${workflowId}`, undefined, setError); }; diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 92f3228..f6a0ee1 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,25 +1,30 @@ -import { BACKEND_API } from "./constants"; +import { BACK_END_URL } from "@/lib/constants"; export default async function apiAuthSignIn( credentials: Partial> | undefined, ) { - const response = await fetch(`${BACKEND_API}/api/login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(credentials), - }); + try { + const response = await fetch(`${BACK_END_URL}/api/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(credentials), + }); - if (response.ok) { - const bearerToken = response.headers.get("authorization"); - const jwt = - bearerToken && bearerToken.slice(0, 7) === "Bearer " - ? bearerToken.slice(7, bearerToken.length) - : ""; - const remoteUser = await response.json(); - return { ...remoteUser, accessToken: jwt }; - } else { - throw new Error("Can not login " + response.status); + if (response.ok) { + const bearerToken = response.headers.get("authorization"); + const jwt = + bearerToken && bearerToken.slice(0, 7) === "Bearer " + ? bearerToken.slice(7, bearerToken.length) + : ""; + const remoteUser = await response.json(); + return { ...remoteUser, accessToken: jwt }; + } else { + throw new Error("Can not login " + response.status); + } + } catch (error) { + console.log(`Login error ${error}`); + throw error; } } diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 8b36d66..5709471 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1 +1,4 @@ -export const BACKEND_API = process.env.NEXT_PUBLIC_BACKEND_API!; +import { env } from "next-runtime-env"; + +export const BASE_URL = env("NEXT_PUBLIC_BASE_URL"); +export const BACK_END_URL = process.env.BACK_END_URL; diff --git a/src/providers/permissions-provider.tsx b/src/providers/permissions-provider.tsx index d6a7829..b12a34d 100644 --- a/src/providers/permissions-provider.tsx +++ b/src/providers/permissions-provider.tsx @@ -10,8 +10,7 @@ import React, { } from "react"; import { useAccessTokenManager } from "@/lib/access-token-manager"; -import { get } from "@/lib/actions/commons.action"; -import { BACKEND_API } from "@/lib/constants"; +import { getUserPermissions } from "@/lib/actions/users.action"; import { useError } from "@/providers/error-provider"; import { PermissionLevel, ResourceId } from "@/types/resources"; @@ -55,20 +54,12 @@ export const PermissionsProvider: React.FC = ({ const userId = session?.user?.id ? Number(session.user.id) : null; - // Fetch permissions - const fetchPermissions = async (userId: number): Promise => { - return get>( - `${BACKEND_API}/api/users/permissions/${userId}`, - setError, - ); - }; - // Make sure session access token is cached useAccessTokenManager(); useEffect(() => { if (status === "authenticated" && userId && permissions.length === 0) { - fetchPermissions(userId).then(setPermissions); + getUserPermissions(userId, setError).then(setPermissions); } }, [status, userId, permissions]);