diff --git a/Dockerfile b/Dockerfile
index 269821a..360f26f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
-RUN npm run build
+RUN npm run build:prod
# 3. Production image, copy all the files and run next
FROM base AS runner
diff --git a/loadEnv.js b/loadEnv.js
new file mode 100644
index 0000000..ea8cec2
--- /dev/null
+++ b/loadEnv.js
@@ -0,0 +1,16 @@
+const fs = require('fs');
+const dotenv = require('dotenv');
+const env = process.argv[2] || 'production'; // Default to production
+
+const envFilePath = `.env.${env}`;
+const localEnvFilePath = `${envFilePath}.local`;
+
+if (fs.existsSync(localEnvFilePath)) {
+ console.log(`Loading environment variables from ${localEnvFilePath}`);
+ dotenv.config({ path: localEnvFilePath });
+} else if (fs.existsSync(envFilePath)) {
+ console.log(`Loading environment variables from ${envFilePath}`);
+ dotenv.config({ path: envFilePath });
+} else {
+ console.error(`No environment file found for ${env}`);
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 6c4244f..250fdf1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,7 +19,9 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cookies-next": "^4.2.1",
+ "cross-env": "^7.0.3",
"date-fns": "^3.6.0",
+ "dotenv": "^16.4.5",
"next": "14.1.3",
"react": "^18",
"react-chartjs-2": "^5.2.0",
@@ -2559,11 +2561,27 @@
"node": ">= 6"
}
},
+ "node_modules/cross-env": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+ "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "bin": {
+ "cross-env": "src/bin/cross-env.js",
+ "cross-env-shell": "src/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=10.14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -2813,6 +2831,17 @@
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.1.tgz",
"integrity": "sha512-HH391uRJXAAeelougod93W++2gECfHIVCqq+B/4znhjCgb2zVPL+iLOVnTYwejqAuNf69Ffc5ILQYdPHsZACJA=="
},
+ "node_modules/dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -4490,8 +4519,7 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/isomorphic-dompurify": {
"version": "0.20.0",
@@ -5254,7 +5282,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -6116,7 +6143,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -6128,7 +6154,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -6932,7 +6957,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
diff --git a/package.json b/package.json
index 5298a78..ffc7131 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
"private": true,
"scripts": {
"dev": "next dev",
- "build": "next build",
+ "build:prod": "node loadEnv.js production && next build",
+ "build:dev": "node loadEnv.js development && next build",
"start": "next start",
"lint": "next lint"
},
@@ -20,7 +21,9 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cookies-next": "^4.2.1",
+ "cross-env": "^7.0.3",
"date-fns": "^3.6.0",
+ "dotenv": "^16.4.5",
"next": "14.1.3",
"react": "^18",
"react-chartjs-2": "^5.2.0",
diff --git a/src/app/(navbar)/patient/visit/[id]/page.js b/src/app/(navbar)/patient/visit/[id]/page.js
index 864a889..8e507d5 100644
--- a/src/app/(navbar)/patient/visit/[id]/page.js
+++ b/src/app/(navbar)/patient/visit/[id]/page.js
@@ -24,7 +24,7 @@ export default function VisitUser({params}){
return ()=> {
isMounted = false;
}
- },[])
+ },[id])
return (
Update Visit Detail Page
diff --git a/src/components/MainNavbar.js b/src/components/MainNavbar.js
index 5806d9d..03297f7 100644
--- a/src/components/MainNavbar.js
+++ b/src/components/MainNavbar.js
@@ -26,7 +26,6 @@ export default function MainNavbar(){
const username = user?.content?.clinicUsername
setUser({username: username, role: user?.content?.role})
}catch(error){
- await handleLogout()
alert(error.message)
router.push('/login')
}
diff --git a/src/components/SessionChecker.js b/src/components/SessionChecker.js
index 2a15289..129e490 100644
--- a/src/components/SessionChecker.js
+++ b/src/components/SessionChecker.js
@@ -1,7 +1,7 @@
"use client"
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
-import { getCookie } from 'cookies-next';
+import { deleteCookie, getCookie } from 'cookies-next';
import { getUserLogin } from '@/actions/formSubmit';
const SessionChecker = () => {
@@ -10,15 +10,20 @@ const SessionChecker = () => {
useEffect(() => {
const interval = setInterval(() => {
const checkValidSession = async()=> {
- const sessionId = getCookie("JSESSIONID" || "");
- const user = await getUserLogin(sessionId)
- if (!user?.content) {
- alert("Session Expired")
- router.push('/login');
+ try{
+ const sessionId = getCookie("JSESSIONID" || "");
+ const user = await getUserLogin(sessionId)
+ if (!user?.content) {
+ deleteCookie("JSESSIONID")
+ router.push('/login');
+ throw new Error("Session Expired")
+ }
+ }catch(error){
+ alert(error.message)
}
}
checkValidSession()
- }, 6000); // Check every 6 sec
+ }, 30000); // Check every 10 min
return () => clearInterval(interval);
}, [router]);
diff --git a/src/components/employee/ManagerForm.js b/src/components/employee/ManagerForm.js
index 1f518f7..85d92d7 100644
--- a/src/components/employee/ManagerForm.js
+++ b/src/components/employee/ManagerForm.js
@@ -1,10 +1,12 @@
"use client"
import { formManagerRegister } from "@/actions/formSubmit";
-import {ButtonForm, UserNameForm, InputForm, SelectForm} from "../form";
-import { useRef, useState } from "react"
+import { ButtonForm, UserNameForm, InputForm, SelectForm } from "../form";
+import { useRef, useState, useEffect } from "react"
+import { Alert } from "@mui/material"
export default function ManagerForm(){
const [role, setRole] = useState('Doctor');
+ const [message,setMessage] = useState(null)
const formRef = useRef(null);
const handleRoleChange = (event) => {
setRole(event.target.value);
@@ -17,34 +19,55 @@ export default function ManagerForm(){
const managerRegister =await formManagerRegister(formData);
formRef.current.reset()
if(managerRegister.error) throw new Error(managerRegister.error)
- alert(managerRegister?.success)
+ setMessage(managerRegister?.success)
}catch(error){
- console.log(error.message)
- alert(error.message)
+ setMessage({error:error.message})
}
}
+ useEffect(()=>{
+ const messageTimeout = setTimeout(()=>{
+ setMessage(null)
+ },1500)
+ return ()=> clearTimeout(messageTimeout)
+ },[message])
return (
-
+ <>
+ {
+ message?.success && (
+
setMessage(null)}>
+ {message?.success}
+
+ )
+ }
+ {
+ message?.error && (
+
setMessage(null)}>
+ {message?.error}
+
+ )
+ }
+
+ >
)
}
\ No newline at end of file
diff --git a/src/components/form/LoginForm.js b/src/components/form/LoginForm.js
index 1a11abf..8024d8f 100644
--- a/src/components/form/LoginForm.js
+++ b/src/components/form/LoginForm.js
@@ -1,25 +1,22 @@
"use client"
import InputForm from "./InputForm";
import ButtonForm from "./ButtonForm";
-import { formLogin } from "@/actions/formSubmit";
+import { formLogin, getUserLogin } from "@/actions/formSubmit";
import { useRef,useEffect, useState } from "react";
import { useRouter } from "next/navigation";
-import { hasCookie,setCookie } from "cookies-next";
+import { deleteCookie, getCookie, hasCookie,setCookie } from "cookies-next";
import Image from "next/image";
export default function LoginForm(){
const formRef = useRef(null);
const router = useRouter();
- const [loading, setLoading] = useState(false)
const handleSubmit = async(e) => {
e.preventDefault()
try {
const formData = new FormData(formRef.current)
formRef.current.reset()
- setLoading(true)
const session = await formLogin(formData);
- console.log(session)
- if(session){
+ if(session?.sessionId){
setCookie("JSESSIONID", session.sessionId)
}else{
alert("Session Not Founded, Bad Credentials")
@@ -32,7 +29,10 @@ export default function LoginForm(){
}
}
useEffect(()=>{
- if(hasCookie("JSESSIONID")){
+ const userLogin = getUserLogin(getCookie("JSESSIONID"));
+ if(!userLogin){
+ deleteCookie("JSESSIONID")
+ }else {
router.push('/dashboard')
}
},[router])
diff --git a/src/components/patient/RegisterForm.js b/src/components/patient/RegisterForm.js
index 77ea82b..160acfd 100644
--- a/src/components/patient/RegisterForm.js
+++ b/src/components/patient/RegisterForm.js
@@ -1,10 +1,12 @@
"use client"
import { patientRegister } from "@/actions/formSubmit";
-import {ButtonForm, InputForm, SelectForm, UserNameForm} from "../form";
-import { useRef } from "react";
+import { ButtonForm, InputForm, SelectForm, UserNameForm } from "../form";
+import { useRef, useState, useEffect } from "react";
+import { Alert } from "@mui/material"
export default function RegisterForm(){
const formRef = useRef(null);
+ const [message, setMessage] = useState(null)
const handleSubmit = async(e) => {
e.preventDefault()
try {
@@ -12,29 +14,51 @@ export default function RegisterForm(){
formRef.current.reset()
const patientRegistration = await patientRegister(formData);
if(patientRegistration.error) throw Error(patientRegistration.error)
- alert(patientRegistration.success)
+ setMessage({success: patientRegistration.success})
}catch(error){
- alert(error.message)
+ setMessage({error:error.message})
}
}
+ useEffect(()=>{
+ const messageTimeout = setTimeout(()=>{
+ setMessage(null)
+ },1500)
+ return ()=> clearTimeout(messageTimeout)
+ },[message])
return (
-
+ <>
+ {
+ message?.success && (
+
setMessage(null)}>
+ {message?.success}
+
+ )
+ }
+ {
+ message?.error && (
+
setMessage(null)}>
+ {message?.error}
+
+ )
+ }
+
+ >
)
}
\ No newline at end of file
diff --git a/src/components/patient/VisitForm.js b/src/components/patient/VisitForm.js
index 3b9f614..e724616 100644
--- a/src/components/patient/VisitForm.js
+++ b/src/components/patient/VisitForm.js
@@ -1,26 +1,42 @@
"use client"
import { getMemberFilter, visitPatientRegister } from "@/actions/formSubmit";
-import {ButtonForm, InputInfoForm} from "../form";
-import { Fragment, useRef, useEffect, useState } from "react";
-// import SearchForm from "../form/SearchForm";
-import {DateTimePicker} from "@mui/x-date-pickers";
+import { ButtonForm } from "../form";
+import { useRef, useEffect, useState } from "react";
+import { Alert, Autocomplete, TextField, ThemeProvider, createTheme } from "@mui/material";
+import { DateTimePicker } from "@mui/x-date-pickers";
import DateTimeProvider from "@/components/DateTimeProvider"
export default function VisitForm () {
+ const customDateTimePickerStyles = {
+ root: {
+ '& .MuiInput-root': {
+ backgroundColor: 'lightblue',
+ },
+ '& .MuiSvgIcon-root': {
+ color: 'red',
+ },
+ '& .MuiPickersPopper-container': {
+ backgroundColor: 'lightgray',
+ },
+ },
+ };
+ const theme = createTheme({
+ components: {
+ MuiPickers: {
+ styleOverrides: {
+ ...customDateTimePickerStyles,
+ },
+ },
+ },
+ });
const [startTime, setStartTime] = useState(new Date())
const [endTime, setEndTime] = useState(new Date())
- const [isFocused1, setIsFocused1] = useState(false)
- const [isFocused2, setIsFocused2] = useState(false)
- const [value1, setValue1] = useState("")
- const [value2, setValue2] = useState("")
- const patientRef = useRef(null)
- const practitionerRef = useRef(null)
const formRef = useRef(null)
const [practitioners, setPractitioners] = useState([])
const [patients, setPatients] = useState([])
+ const [message, setMessage] = useState(null);
useEffect(()=>{
try {
-
const fetchMember = async() => {
const [patient, practitioner] = await Promise.all([
getMemberFilter({role: "ROLE_PATIENT"}),
@@ -31,21 +47,13 @@ export default function VisitForm () {
}
fetchMember()
}catch(error){
- alert("Server Error")
+ setMessage("Server Error")
}
},[])
- const checkFocus = () => {
- if(patientRef.current && practitionerRef.current){
- setIsFocused1(document.activeElement === patientRef.current)
- setIsFocused2(document.activeElement === practitionerRef.current)
- }
- }
- const handleValue1 = (e) => {
- setValue1(e.target.value)
- }
- const handleValue2 = (e) => {
- setValue2(e.target.value)
- }
+ const patientsFirstName = new Set(patients?.map(patient => patient?.firstName))
+ const patientsLastName = new Set(patients?.map(patient => patient?.lastName))
+ const practitionersFirstName = new Set(practitioners?.map(practitioner => practitioner?.firstName))
+ const practitionersLastName = new Set(practitioners?.map(practitioner => practitioner?.lastName))
const handleSubmit = async(e) => {
e.preventDefault()
try {
@@ -55,72 +63,82 @@ export default function VisitForm () {
formData.append("endTime",endTime)
const visitPatientRegistration = await visitPatientRegister(formData);
if(visitPatientRegistration.error) throw Error(visitPatientRegistration.error)
- alert(visitPatientRegistration.success)
+ setMessage({success:visitPatientRegistration?.success})
}catch(error){
- alert(error.message)
+ setMessage({error:error?.message})
}
}
+ useEffect(()=>{
+ const messageTimeout = setTimeout(()=>{
+ setMessage(null)
+ },1500)
+ return ()=> clearTimeout(messageTimeout)
+ },[message])
return (
-
+
+ >
)
}
diff --git a/src/middleware.js b/src/middleware.js
index 1a62450..dfbaaa4 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -7,8 +7,7 @@ export function middleware(req) {
const sessionId = parsedCookie.JSESSIONID;
if (!sessionId && req.nextUrl.pathname !=="/login") {
return NextResponse.redirect(new URL('/login', req.url));
- }
- else if(req.nextUrl.pathname === "/patient"){
+ }else if(req.nextUrl.pathname === "/patient"){
return NextResponse.redirect(new URL('/patient/register', req.url))
}else if(req.nextUrl.pathname === "/employee"){
return NextResponse.redirect(new URL('/employee/dashboard', req.url))
diff --git a/tailwind.config copy.js b/tailwind.config copy.js
deleted file mode 100644
index 0ad31b4..0000000
--- a/tailwind.config copy.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- content: [
- "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
- ],
- /* fff9f9
- 002741
- e59be9
- ddeffb
- dde0fb
- */
- theme: {
- extend: {
- backgroundImage: {
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
- "gradient-conic":
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
- },
- colors: {
- "primary":"#002741",
- "active": "#e59be9",
- "dark":"#fff9f9",
- "muted":"#00274170",
- "dark-muted":"#dde0fbb2"
- },
- backgroundColor: {
- "primary": "#fff9f9",
- "dark":"#002741",
- "secondary": "#021111f9"
- },
- screens: {
- "xm": "1110px"
- }
- },
- },
- plugins: [],
-};