Skip to content

Commit e82d692

Browse files
authored
Merge pull request #62 from PentabyteDevAlign/refactor
Refactor
2 parents f989c0b + 2917c4b commit e82d692

File tree

9 files changed

+485
-306
lines changed

9 files changed

+485
-306
lines changed

Frontend/src/App.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ function App() {
198198
element={
199199
<ProtectedRoute>
200200
<AppLayout>
201-
{role == "manager" ? <ManagerTeam /> : <StaffTeam />}
201+
<ManagerTeam />
202202
</AppLayout>
203203
</ProtectedRoute>
204204
}

Frontend/src/api/ai.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import axios from "axios";
2+
3+
const apiAI = axios.create({
4+
baseURL: import.meta.env.VITE_AI_URL || "http://localhost:3500",
5+
headers: {
6+
"Content-Type": "application/json",
7+
},
8+
});
9+
10+
apiAI.interceptors.request.use(
11+
(config) => {
12+
const token = localStorage.getItem("token");
13+
if (token) {
14+
config.headers.Authorization = `Bearer ${token}`;
15+
}
16+
return config;
17+
},
18+
(error) => Promise.reject(error)
19+
);
20+
21+
apiAI.interceptors.response.use(
22+
(response) => response,
23+
(error) => {
24+
if (error.response?.status === 401) {
25+
console.warn("Unauthorized — maybe token expired");
26+
}
27+
return Promise.reject(error);
28+
}
29+
);
30+
31+
export default apiAI;

Frontend/src/pages/PM/ProjectDetails.jsx renamed to Frontend/src/components/ProjectDetails.jsx

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ import {
1717
AlertDialogHeader,
1818
AlertDialogTitle,
1919
} from "@/components/ui/alert-dialog";
20-
import projectService from "../../services/project.service";
20+
import projectService from "../services/project.service";
2121
import { Button } from "@/components/ui/button";
2222
import { CircleCheckBig, Trash } from "lucide-react";
2323
import { toast } from "@/lib/toast";
24+
import Loading from "@/components/Loading";
2425

2526
// ─── Utility Helpers ──────────────────────────────────────────────
2627
const getStatusColor = (status) => {
@@ -52,16 +53,20 @@ export default function ProjectDetailsDialog({
5253
onClose,
5354
onProjectUpdated,
5455
}) {
55-
const { role } = useAuthStore();
56-
const isHR = role === "hr";
5756
const [project, setProject] = useState(null);
5857
const [manager, setManager] = useState(null);
5958
const [staff, setStaff] = useState([]);
60-
const [isLoading, setIsLoading] = useState(true);
6159
const [isEditing, setIsEditing] = useState(false);
6260
const [isSaving, setIsSaving] = useState(false);
6361
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
6462

63+
const [loadingState, setLoadingState] = useState(false);
64+
const [loadingText, setLoadingText] = useState("");
65+
66+
const { role } = useAuthStore();
67+
const isHR = role === "hr";
68+
const isManager = role === "manager";
69+
6570
const [formData, setFormData] = useState({
6671
name: "",
6772
description: "",
@@ -79,14 +84,13 @@ export default function ProjectDetailsDialog({
7984
if (!isOpen || !projectId) {
8085
if (!isOpen) {
8186
setProject(null);
82-
setIsLoading(true);
8387
}
8488
return;
8589
}
8690

8791
const loadData = async () => {
88-
setIsLoading(true);
89-
92+
setLoadingState(true);
93+
setLoadingText("Getting data...");
9094
try {
9195
const [projectRes, tasksRes, skillsRes, employeesRes] =
9296
await Promise.allSettled([
@@ -145,7 +149,8 @@ export default function ProjectDetailsDialog({
145149
type: "error",
146150
});
147151
} finally {
148-
setIsLoading(false);
152+
setLoadingState(false);
153+
setLoadingText("");
149154
}
150155
};
151156

@@ -160,6 +165,8 @@ export default function ProjectDetailsDialog({
160165

161166
const handleSave = async () => {
162167
setIsSaving(true);
168+
setLoadingState(true);
169+
setLoadingText("Updating the task...");
163170
try {
164171
await projectService.updateProject(projectId, {
165172
name: formData.name,
@@ -201,11 +208,14 @@ export default function ProjectDetailsDialog({
201208
} finally {
202209
setIsSaving(false);
203210
setIsEditing(false);
211+
setLoadingState(false);
212+
setLoadingText("");
204213
}
205214
};
206215

207216
const handleDelete = async () => {
208-
setIsLoading(true);
217+
setLoadingState(true);
218+
setLoadingText("Delete projects...");
209219
try {
210220
await projectService.deleteProject(projectId);
211221
toast("Project deleted successfully", {
@@ -222,13 +232,15 @@ export default function ProjectDetailsDialog({
222232
type: "error",
223233
});
224234
} finally {
225-
setIsLoading(false);
235+
setLoadingState(false);
236+
setLoadingText("");
226237
}
227238
};
228239

229240
const handleComplete = async () => {
230241
if (!confirm("Mark this project as completed?")) return;
231-
setIsLoading(true);
242+
setLoadingState(true);
243+
setLoadingText("Mark project as completed...");
232244
try {
233245
const res = await projectService.updateProjectStatus(
234246
projectId,
@@ -251,20 +263,38 @@ export default function ProjectDetailsDialog({
251263
type: "error",
252264
});
253265
} finally {
254-
setIsLoading(false);
266+
setLoadingState(false);
267+
setLoadingText("");
255268
}
256269
};
257270

258271
// ─── Render ──────────────────────────────────────────────
259272
return (
260273
<>
261-
<Dialog open={isOpen} onOpenChange={onClose}>
274+
<Loading status={loadingState} fullscreen text={loadingText} />
275+
<Dialog
276+
open={isOpen}
277+
onOpenChange={(open) => {
278+
if (!open) {
279+
// Dialog is closing — reset your edit mode and form
280+
setIsEditing(false);
281+
setFormData(
282+
project
283+
? {
284+
name: project.name,
285+
description: project.description,
286+
startDate: project.startDate?.slice(0, 10) || "",
287+
deadline: project.deadline?.slice(0, 10) || "",
288+
}
289+
: {}
290+
);
291+
}
292+
293+
onClose?.(open); // Call parent handler if you have one
294+
}}
295+
>
262296
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
263-
{isLoading || isSaving ? (
264-
<div className="py-12 text-center">
265-
<p className="text-gray-500">Loading project details...</p>
266-
</div>
267-
) : project ? (
297+
{project ? (
268298
<>
269299
<DialogHeader>
270300
<DialogTitle className="text-2xl font-bold mr-10">
@@ -279,7 +309,7 @@ export default function ProjectDetailsDialog({
279309
) : (
280310
<>
281311
{project.name}
282-
{!isHR && (
312+
{isManager && (
283313
<Button
284314
variant="ghost"
285315
size="icon-sm"
@@ -323,6 +353,7 @@ export default function ProjectDetailsDialog({
323353
name="startDate"
324354
value={formData.startDate}
325355
onChange={handleInputChange}
356+
min={new Date().toISOString().split("T")[0]}
326357
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
327358
/>
328359
) : (
@@ -342,6 +373,11 @@ export default function ProjectDetailsDialog({
342373
name="deadline"
343374
value={formData.deadline}
344375
onChange={handleInputChange}
376+
min={
377+
formData.startDate
378+
? formData.startDate
379+
: new Date().toISOString().split("T")[0]
380+
}
345381
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
346382
/>
347383
) : (
@@ -426,11 +462,19 @@ export default function ProjectDetailsDialog({
426462

427463
{/* Buttons */}
428464
<div className="flex gap-3 pt-4 border-t">
429-
{!isHR &&
465+
{isManager &&
430466
(isEditing ? (
431467
<>
432468
<button
433-
onClick={() => setIsEditing(false)}
469+
onClick={() => {
470+
setIsEditing(false);
471+
setFormData({
472+
name: project?.name || "",
473+
description: project?.description || "",
474+
startDate: project?.startDate?.slice(0, 10) || "",
475+
deadline: project?.deadline?.slice(0, 10) || "",
476+
});
477+
}}
434478
className="flex-1 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 font-medium cursor-pointer"
435479
>
436480
Cancel

0 commit comments

Comments
 (0)