chore: update eslint and prettier configuration
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
@@ -12,8 +18,17 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Loader2, Check, ArrowUp, ArrowDown } from 'lucide-react';
|
||||
import { projectService, packageService, chainageService } from '@/services/api';
|
||||
import { Project, Package as PackageType, Chainage, SessionContext } from '@/types';
|
||||
import {
|
||||
projectService,
|
||||
packageService,
|
||||
chainageService,
|
||||
} from '@/services/api';
|
||||
import {
|
||||
Project,
|
||||
Package as PackageType,
|
||||
Chainage,
|
||||
SessionContext,
|
||||
} from '@/types';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
type ProjectSelectionSectionProps = {
|
||||
@@ -26,21 +41,27 @@ type ProjectSelectionSectionProps = {
|
||||
let globalProjectsCache: Project[] | null = null;
|
||||
let projectsPromise: Promise<Project[]> | null = null;
|
||||
|
||||
export function ProjectSelectionSection({
|
||||
onSelectionComplete,
|
||||
export function ProjectSelectionSection({
|
||||
onSelectionComplete,
|
||||
onSelectionChange,
|
||||
asStep = false,
|
||||
hideButton = false
|
||||
hideButton = false,
|
||||
}: ProjectSelectionSectionProps) {
|
||||
// Data states
|
||||
const [projects, setProjects] = useState<Project[]>(globalProjectsCache || []);
|
||||
const [projects, setProjects] = useState<Project[]>(
|
||||
globalProjectsCache || [],
|
||||
);
|
||||
const [packages, setPackages] = useState<PackageType[]>([]);
|
||||
const [chainages, setChainages] = useState<Chainage[]>([]);
|
||||
|
||||
// Selection states
|
||||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||
const [selectedPackage, setSelectedPackage] = useState<PackageType | null>(null);
|
||||
const [selectedChainage, setSelectedChainage] = useState<Chainage | null>(null);
|
||||
const [selectedPackage, setSelectedPackage] = useState<PackageType | null>(
|
||||
null,
|
||||
);
|
||||
const [selectedChainage, setSelectedChainage] = useState<Chainage | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
// Loading states
|
||||
const [loadingProjects, setLoadingProjects] = useState(!globalProjectsCache);
|
||||
@@ -53,7 +74,7 @@ export function ProjectSelectionSection({
|
||||
// Load projects on mount
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
|
||||
const loadProjects = async () => {
|
||||
// Use cache if we already have it
|
||||
if (globalProjectsCache) {
|
||||
@@ -66,13 +87,16 @@ export function ProjectSelectionSection({
|
||||
|
||||
// If a fetch is already in flight, reuse that promise
|
||||
if (!projectsPromise) {
|
||||
projectsPromise = projectService.getProjects().then(data => {
|
||||
globalProjectsCache = data.items;
|
||||
return data.items;
|
||||
}).catch(err => {
|
||||
projectsPromise = null; // Reset on error to allow retry
|
||||
throw err;
|
||||
});
|
||||
projectsPromise = projectService
|
||||
.getProjects()
|
||||
.then((data) => {
|
||||
globalProjectsCache = data.items;
|
||||
return data.items;
|
||||
})
|
||||
.catch((err) => {
|
||||
projectsPromise = null; // Reset on error to allow retry
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -93,7 +117,9 @@ export function ProjectSelectionSection({
|
||||
};
|
||||
|
||||
loadProjects();
|
||||
return () => { isMounted = false; };
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Load packages when project changes
|
||||
@@ -112,7 +138,9 @@ export function ProjectSelectionSection({
|
||||
setSelectedPackage(null);
|
||||
setSelectedChainage(null);
|
||||
setChainages([]);
|
||||
const data = await packageService.getPackagesByProject(selectedProject.id);
|
||||
const data = await packageService.getPackagesByProject(
|
||||
selectedProject.id,
|
||||
);
|
||||
if (isMounted) {
|
||||
setPackages(data.items);
|
||||
}
|
||||
@@ -128,7 +156,9 @@ export function ProjectSelectionSection({
|
||||
}
|
||||
};
|
||||
loadPackages();
|
||||
return () => { isMounted = false; };
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [selectedProject]);
|
||||
|
||||
// Load chainages when package changes
|
||||
@@ -145,7 +175,9 @@ export function ProjectSelectionSection({
|
||||
setLoadingChainages(true);
|
||||
setError(null);
|
||||
setSelectedChainage(null);
|
||||
const data = await chainageService.getChainagesByPackage(selectedPackage.id);
|
||||
const data = await chainageService.getChainagesByPackage(
|
||||
selectedPackage.id,
|
||||
);
|
||||
if (isMounted) {
|
||||
setChainages(data.items);
|
||||
}
|
||||
@@ -161,7 +193,9 @@ export function ProjectSelectionSection({
|
||||
}
|
||||
};
|
||||
loadChainages();
|
||||
return () => { isMounted = false; };
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [selectedPackage]);
|
||||
|
||||
const handleProjectChange = (projectId: string) => {
|
||||
@@ -185,13 +219,14 @@ export function ProjectSelectionSection({
|
||||
// Handle change reporting
|
||||
useEffect(() => {
|
||||
if (onSelectionChange) {
|
||||
const currentIds = selectedProject && selectedPackage && selectedChainage
|
||||
? `${selectedProject.id}-${selectedPackage.id}-${selectedChainage.id}`
|
||||
: null;
|
||||
const currentIds =
|
||||
selectedProject && selectedPackage && selectedChainage
|
||||
? `${selectedProject.id}-${selectedPackage.id}-${selectedChainage.id}`
|
||||
: null;
|
||||
|
||||
if (currentIds !== lastReportedIdRef.current) {
|
||||
lastReportedIdRef.current = currentIds;
|
||||
|
||||
|
||||
if (selectedProject && selectedPackage && selectedChainage) {
|
||||
onSelectionChange({
|
||||
projectId: selectedProject.id,
|
||||
@@ -210,7 +245,12 @@ export function ProjectSelectionSection({
|
||||
}, [selectedProject, selectedPackage, selectedChainage, onSelectionChange]);
|
||||
|
||||
const handleProceed = () => {
|
||||
if (selectedProject && selectedPackage && selectedChainage && onSelectionComplete) {
|
||||
if (
|
||||
selectedProject &&
|
||||
selectedPackage &&
|
||||
selectedChainage &&
|
||||
onSelectionComplete
|
||||
) {
|
||||
onSelectionComplete({
|
||||
projectId: selectedProject.id,
|
||||
projectName: selectedProject.name,
|
||||
@@ -228,8 +268,18 @@ export function ProjectSelectionSection({
|
||||
// Step status helpers
|
||||
const getStepStatus = (step: number) => {
|
||||
if (step === 1) return selectedProject ? 'completed' : 'active';
|
||||
if (step === 2) return selectedPackage ? 'completed' : selectedProject ? 'active' : 'pending';
|
||||
if (step === 3) return selectedChainage ? 'completed' : selectedPackage ? 'active' : 'pending';
|
||||
if (step === 2)
|
||||
return selectedPackage
|
||||
? 'completed'
|
||||
: selectedProject
|
||||
? 'active'
|
||||
: 'pending';
|
||||
if (step === 3)
|
||||
return selectedChainage
|
||||
? 'completed'
|
||||
: selectedPackage
|
||||
? 'active'
|
||||
: 'pending';
|
||||
return 'pending';
|
||||
};
|
||||
|
||||
@@ -291,7 +341,9 @@ export function ProjectSelectionSection({
|
||||
</div>
|
||||
) : (
|
||||
<SelectValue
|
||||
placeholder={selectedProject ? 'Select package' : 'Select project first'}
|
||||
placeholder={
|
||||
selectedProject ? 'Select package' : 'Select project first'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</SelectTrigger>
|
||||
@@ -323,7 +375,9 @@ export function ProjectSelectionSection({
|
||||
</div>
|
||||
) : (
|
||||
<SelectValue
|
||||
placeholder={selectedPackage ? 'Select segment' : 'Select package first'}
|
||||
placeholder={
|
||||
selectedPackage ? 'Select segment' : 'Select package first'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</SelectTrigger>
|
||||
@@ -331,9 +385,13 @@ export function ProjectSelectionSection({
|
||||
{chainages.map((chn) => (
|
||||
<SelectItem key={chn.id} value={chn.id}>
|
||||
<div className="flex flex-col gap-0.5 py-0.5">
|
||||
<span className="font-semibold text-sm">{chn.segment_name}</span>
|
||||
<span className="font-semibold text-sm">
|
||||
{chn.segment_name}
|
||||
</span>
|
||||
<div className="flex items-center gap-2 text-[10px] text-muted-foreground font-medium">
|
||||
<span>{chn.chainage_start_km}-{chn.chainage_end_km} km</span>
|
||||
<span>
|
||||
{chn.chainage_start_km}-{chn.chainage_end_km} km
|
||||
</span>
|
||||
<span className="h-2.5 w-px bg-border" />
|
||||
<span className="flex items-center gap-1 uppercase">
|
||||
{chn.direction === 'UP' ? (
|
||||
@@ -399,9 +457,12 @@ export function ProjectSelectionSection({
|
||||
<CardHeader className="pb-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div>
|
||||
<CardTitle className="text-2xl font-bold">Select Project Segment</CardTitle>
|
||||
<CardTitle className="text-2xl font-bold">
|
||||
Select Project Segment
|
||||
</CardTitle>
|
||||
<CardDescription className="mt-2 text-base">
|
||||
Select Project, Package & Segment to begin intelligent road analysis.
|
||||
Select Project, Package & Segment to begin intelligent road
|
||||
analysis.
|
||||
</CardDescription>
|
||||
</div>
|
||||
|
||||
@@ -423,12 +484,18 @@ export function ProjectSelectionSection({
|
||||
: 'bg-muted text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{status === 'completed' ? <Check className="h-5 w-5" /> : step}
|
||||
{status === 'completed' ? (
|
||||
<Check className="h-5 w-5" />
|
||||
) : (
|
||||
step
|
||||
)}
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
'text-xs mt-2 font-medium',
|
||||
status === 'pending' ? 'text-muted-foreground/60' : 'text-foreground',
|
||||
status === 'pending'
|
||||
? 'text-muted-foreground/60'
|
||||
: 'text-foreground',
|
||||
)}
|
||||
>
|
||||
{labels[index]}
|
||||
@@ -438,7 +505,9 @@ export function ProjectSelectionSection({
|
||||
<div
|
||||
className={cn(
|
||||
'w-16 h-0.5 mx-2 mb-6 rounded-full',
|
||||
getStepStatus(step + 1) !== 'pending' ? 'bg-primary' : 'bg-border',
|
||||
getStepStatus(step + 1) !== 'pending'
|
||||
? 'bg-primary'
|
||||
: 'bg-border',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
@@ -449,9 +518,7 @@ export function ProjectSelectionSection({
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0">
|
||||
{content}
|
||||
</CardContent>
|
||||
<CardContent className="pt-0">{content}</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user