Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions myhaki/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions myhaki/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@heroicons/react": "^2.2.0",
"js-cookie": "^3.0.5",
"lucide-react": "^0.544.0",
"next": "15.5.3",
"next-auth": "^4.24.11",
"react": "19.1.0",
Expand Down
2 changes: 1 addition & 1 deletion myhaki/src/app/authentication/sign-in/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ describe("SignInPage", () => {
const container = screen.getByText('Invalid credentials').parentElement;
expect(container).not.toBeNull();
});
});
});
37 changes: 26 additions & 11 deletions myhaki/src/app/authentication/sign-in/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ import { useState } from 'react';
import useFetchSignin from '@/app/hooks/useFetchSignIn';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
import { Eye, EyeOff } from 'lucide-react';


export default function Signin() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { signin, loading, error } = useFetchSignin();
const [showPassword, setShowPassword] = useState(false);
const router = useRouter();

async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
try {
await signin(email, password);
router.push('/profile');
router.push('/dashboard');
} catch {
}
}
Expand Down Expand Up @@ -51,19 +54,31 @@ export default function Signin() {
className="border rounded w-full py-2 px-3 mb-6 focus:outline-none"
/>


<label htmlFor="password" className="block mb-2 text-gray-700 font-medium">
Password
</label>
<input
type="password"
id="password"
placeholder="Your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
autoComplete="current-password"
className="border rounded w-full py-2 px-3 mb-6 focus:outline-none"
/>
<div className="relative mb-6">
<input
type={showPassword ? 'text' : 'password'}
id="password"
placeholder="Your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
autoComplete="current-password"
className="border rounded w-full py-2 px-3 pr-10 focus:outline-none"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
aria-label={showPassword ? 'Hide password' : 'Show password'}
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-600"
>
{showPassword ? <EyeOff size={20} /> : <Eye size={20} />}
</button>
</div>


<div className="flex justify-end mb-6">
<a
Expand Down
75 changes: 39 additions & 36 deletions myhaki/src/app/cases/components/Case-Detail-Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
import { useEffect } from 'react';
import { CaseItem } from '@/app/utils/type';

interface Dependents {
count: number;
description: string;
}

interface CaseDetailModalProps {
caseItem: CaseItem;
onClose: () => void;
Expand All @@ -24,14 +19,26 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
return () => window.removeEventListener('keydown', handleEsc);
}, [onClose]);

const formatDate = (dateStr: string) => {
const formatDate = (dateStr?: string) => {
if (!dateStr) return 'N/A';
const date = new Date(dateStr);
return isNaN(date.getTime()) ? 'Invalid Date' : date.toLocaleDateString();
};

const safeCapitalize = (str?: string) => {
if (!str) return 'N/A';
return str.charAt(0).toUpperCase() + str.slice(1);
};

const safeReplaceAndCapitalize = (str?: string) => {
if (!str) return 'N/A';
const replaced = str.replace('_', ' ');
return replaced.charAt(0).toUpperCase() + replaced.slice(1);
};

return (
<div className="fixed inset-0 bg-black/45 bg-opacity-10 flex items-center justify-center z-50">
<div className="bg-white rounded-2xl shadow-2xl p-6 w-full max-w-2xl max-h-[90vh]">
<div className="fixed inset-0 bg-black/45 flex items-center justify-center z-50">
<div className="bg-white rounded-2xl shadow-2xl p-6 w-full max-w-2xl max-h-[90vh] overflow-y-auto">
<h2 className="text-2xl font-bold text-[#822727] mb-6">Case Details - Case ID: {caseItem.case_id}</h2>

<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
Expand All @@ -46,58 +53,56 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
</p>
<p className="text-sm text-gray-600">
<span className="font-medium">Gender:</span>{' '}
{caseItem.detainee_details.gender.charAt(0).toUpperCase() + caseItem.detainee_details.gender.slice(1)}
{safeCapitalize(caseItem.detainee_details.gender)}
</p>
<p className="text-sm text-gray-600">
<span className="font-medium">Date of Birth:</span>{' '}
{formatDate(caseItem.detainee_details.date_of_birth)}
</p>
<p className="text-sm text-gray-600">
<span className="font-medium">Relation to Applicant:</span>{' '}
{caseItem.detainee_details.relation_to_applicant.charAt(0).toUpperCase() +
caseItem.detainee_details.relation_to_applicant.slice(1) || 'N/A'}
{safeCapitalize(caseItem.detainee_details.relation_to_applicant)}
</p>
</div>

<div>
<h3 className="text-lg font-semibold text-gray-800 mb-3">Case Information</h3>
<h3 className="text-lg font-semibold text-gray-800 mb-3">Case Information</h3>
<p className="text-sm mb-1.5 text-gray-600">
<span className="font-medium">Case Type:</span>{' '}
{caseItem.predicted_case_type.charAt(0).toUpperCase() + caseItem.predicted_case_type.slice(1) || 'N/A'}
{safeCapitalize(caseItem.predicted_case_type)}
</p>
<p className="text-sm mb-1.5 text-gray-600">
<span className="font-medium">Urgency Level:</span>{' '}
<span className={
caseItem.predicted_urgency_level?.toLowerCase() === 'high' ? 'text-red-500 font-semibold' :
<span
className={
caseItem.predicted_urgency_level?.toLowerCase() === 'high' ? 'text-red-500 font-semibold' :
caseItem.predicted_urgency_level?.toLowerCase() === 'medium' ? 'text-blue-500 font-semibold' :
caseItem.predicted_urgency_level?.toLowerCase() === 'low' ? 'text-green-700 font-semibold' :
''
}>
caseItem.predicted_urgency_level?.toLowerCase() === 'low' ? 'text-green-700 font-semibold' :
''
}
>
{caseItem.predicted_urgency_level
? caseItem.predicted_urgency_level.charAt(0).toUpperCase() + caseItem.predicted_urgency_level.slice(1)
? safeCapitalize(caseItem.predicted_urgency_level)
: 'N/A'}
</span>
</p>
<p className="text-sm mb-1.5 text-gray-600">
<span className="font-medium">Status:</span>{' '}
<span
className={`inline-flex px-3 py-1 text-xs font-semibold rounded-full capitalize ${caseItem.status.toLowerCase() === 'pending'
? 'bg-red-800 text-red-100'
: caseItem.status.toLowerCase() === 'accepted'
? 'bg-[#f1c08b] text-gray-600'
: caseItem.status.toLowerCase() === 'completed'
? 'bg-green-600 text-green-100'
: caseItem.status.toLowerCase() === 'in_progress'
? 'bg-blue-100 text-blue-800'
: 'bg-gray-100 text-gray-800'
}`}
className={`inline-flex px-3 py-1 text-xs font-semibold rounded-full capitalize ${
caseItem.status.toLowerCase() === 'pending' ? 'bg-red-800 text-red-100' :
caseItem.status.toLowerCase() === 'accepted' ? 'bg-[#f1c08b] text-gray-600' :
caseItem.status.toLowerCase() === 'completed' ? 'bg-green-600 text-green-100' :
caseItem.status.toLowerCase() === 'in_progress' ? 'bg-blue-100 text-blue-800' :
'bg-gray-100 text-gray-800'
}`}
>
{caseItem.status}
</span>
</p>
<p className="text-sm mb-1.5 text-gray-600">
<span className="font-medium">Stage:</span>{' '}
{caseItem.stage.replace('_', ' ').charAt(0).toUpperCase() + caseItem.stage.replace('_', ' ').slice(1) || 'N/A'}
{safeReplaceAndCapitalize(caseItem.stage)}
</p>
<p className="text-sm mb-1.5 text-gray-600">
<span className="font-medium">Date of Offense:</span>{' '}
Expand All @@ -114,7 +119,7 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
<h3 className="text-lg font-semibold text-gray-800 mb-3">Case Description</h3>
<p className="text-sm text-gray-600">
{caseItem.case_description
? caseItem.case_description.charAt(0).toUpperCase() + caseItem.case_description.slice(1)
? safeCapitalize(caseItem.case_description)
: 'No description provided.'}
</p>
</div>
Expand All @@ -130,12 +135,11 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
<h3 className="text-lg font-semibold text-gray-800 mb-3">Financial Information</h3>
<p className="text-sm text-gray-600">
<span className="font-medium">Income Source:</span>{' '}
{caseItem.income_source.charAt(0).toUpperCase() + caseItem.income_source.slice(1) || 'N/A'}
{safeCapitalize(caseItem.income_source)}
</p>
<p className="text-sm text-gray-600">
<span className="font-medium">Monthly Income:</span>{' '}
{caseItem.monthly_income.replace('_', ' ').charAt(0).toUpperCase() +
caseItem.monthly_income.replace('_', ' ').slice(1) || 'N/A'}
{safeReplaceAndCapitalize(caseItem.monthly_income)}
</p>
<p className="text-sm text-gray-600">
<span className="font-medium">Dependents:</span>{' '}
Expand All @@ -144,7 +148,6 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
: 'N/A'}
</p>
</div>
Property 'toString' does not exist on type 'never'.ts(2339)

<div className="mt-8 flex justify-end">
<button
Expand All @@ -157,4 +160,4 @@ export default function CaseDetailModal({ caseItem, onClose }: CaseDetailModalPr
</div>
</div>
);
}
}
4 changes: 2 additions & 2 deletions myhaki/src/app/cases/components/Case-Status-Bar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export default function CaseStatusBar() {
<CaseTable />
</main>

<aside className="w-full overflow-x-hidden lg:w-1/4 px-4 py-40 flex flex-row lg:flex-col gap-6 lg:gap-10
<aside className="w-full lg:w-1/4 px-4 py-40 flex flex-row lg:flex-col gap-6 lg:gap-10
lg:sticky lg:top-0 [@media(width:1024px)]:ml-[-2%] [@media(width:1024px)]:mt-[-4%] ">

<div className="bg-[#b8906e] [@media(width:1024px)]:w-33 [@media(width:1366px)]:w-56 [@media(width:1366px)]:h-79 h-20 text-white rounded-lg mb-10 mt-[-20%] px-8 py-4 flex-1 flex flex-col items-center text-center [@media(width:1366px)]:mt-[-30%] [@media(width:1280px)]:h-79 [@media(width:1280px)]:mt-[-33%] [@media(width:1024px)]:ml-[-20%] [@media(width:1024px)]:h-[75%]">
<div className="bg-[#b8906e] [@media(width:1024px)]:w-33 [@media(width:1366px)]:w-56 [@media(width:1366px)]:h-79 text-white rounded-lg mb-10 mt-[-20%] px-8 py-4 flex-1 flex flex-col items-center text-center [@media(width:1512px)]:mt-[-27%] [@media(width:1366px)]:mt-[-30%] [@media(width:1280px)]:h-79 [@media(width:1280px)]:mt-[-33%] [@media(width:1024px)]:ml-[-20%] [@media(width:1024px)]:h-[75%]">
{loading ? (
<span className="mt-8 text-5xl [@media(width:1024px)]:text-[120%] font-bold">...</span>
) : (
Expand Down
2 changes: 1 addition & 1 deletion myhaki/src/app/cases/components/Cases-Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default function CaseTable() {
};

return (
<div className="bg-white rounded-2xl [@media(width:1024px)]:ml-[-10%] shadow-xl p-6 overflow-hidden -mt-7">
<div className="bg-white rounded-2xl [@media(width:1024px)]:ml-[-10%] mb-3 shadow-xl p-6 overflow-hidden -mt-7">
<div className="mb-1">
<div className="mt-4 flex flex-col sm:flex-row gap-3 items-start sm:items-center">
<input
Expand Down
5 changes: 2 additions & 3 deletions myhaki/src/app/cases/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import Layout from '../shared-components/Layout';
export default function Cases() {
return (

<div className='h-screen overflow-hidden'>
<div className='h-screen overflow-hidden [@media(width:1024px)]:overflow-scroll [@media(width:1280px)]:overflow-scroll'>
<Layout>
<main className="flex-1 px-4 md:px-8 py-8 overflow-hidden">
<main className="flex-1 px-4 md:px-8 py-8 overflow-hidden [@media(width:1024px)]:overflow-scroll">
<CaseStatusBar />
</main>
</Layout>
</div>

);
}
4 changes: 2 additions & 2 deletions myhaki/src/app/dashboard/components/CaseTrends/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ function Legend({ pieItems }: { pieItems: PieItem[] }) {
{pieItems.map((pieItem) => (
<li key={pieItem.value} className="flex items-center gap-1">
<span
className="inline-block w-3 xl:ml-[-65px] h-3 rounded-full"
className="inline-block w-3 xl:ml-[-15px] h-3 rounded-full"
style={{ backgroundColor: pieItem.color }}
/>
<span className="text-sm xl:text-xl text-[#621616] ">{pieItem.value}</span>
<span className="text-sm xl:text-xl text-[#621616] ">{pieItem.value}</span>
</li>
))}
</ul>
Expand Down
2 changes: 1 addition & 1 deletion myhaki/src/app/lawyers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default function LawyersPage() {

return (
<div className="flex bg-gray-50 min-h-screen">
<div className="shrink-0">
<div className="w-64 shrink-0">
<Sidebar />
</div>

Expand Down
Loading