188 lines
6.9 KiB
JavaScript
188 lines
6.9 KiB
JavaScript
// src/components/CollegeProfileList.js
|
||
import React, { useEffect, useState } from "react";
|
||
import { Link, useNavigate, useParams } from "react-router-dom";
|
||
import CareerSelectDropdown from "./CareerSelectDropdown.js";
|
||
import apiFetch from '../auth/apiFetch.js';
|
||
|
||
export default function CollegeProfileList() {
|
||
const { careerId } = useParams(); // may be undefined
|
||
const navigate = useNavigate();
|
||
|
||
/* ───────── existing lists ───────── */
|
||
const [rows, setRows] = useState([]);
|
||
const [careerRows, setCareerRows] = useState([]);
|
||
|
||
/* ───────── ui state ───────── */
|
||
const [showPicker, setShowPicker] = useState(false);
|
||
const [loadingCareers, setLoadingCareers] = useState(true);
|
||
|
||
const authFetch = apiFetch;
|
||
|
||
/* ───────── load college plans ───────── */
|
||
/* ───────── load college plans ───────── */
|
||
useEffect(() => {
|
||
(async () => {
|
||
try {
|
||
const r = await authFetch("/api/premium/college-profile/all");
|
||
if (!r.ok) throw new Error(`load college-profile/all → ${r.status}`);
|
||
const d = await r.json();
|
||
setRows(d.collegeProfiles || []);
|
||
} catch (err) {
|
||
console.error("College profiles load failed:", err);
|
||
setRows([]);
|
||
}
|
||
})();
|
||
}, []);
|
||
|
||
/* ───────── load career profiles for the picker ───────── */
|
||
useEffect(() => {
|
||
(async () => {
|
||
try {
|
||
const res = await authFetch("/api/premium/career-profile/all");
|
||
if (!res.ok) throw new Error(`load career-profile/all → ${res.status}`);
|
||
const data = await res.json();
|
||
setCareerRows(data.careerProfiles || []);
|
||
} catch (err) {
|
||
console.error("Career profiles load failed:", err);
|
||
} finally {
|
||
setLoadingCareers(false);
|
||
}
|
||
})();
|
||
}, []);
|
||
|
||
/* ───────── delete helper ───────── */
|
||
async function handleDelete(row) {
|
||
if (!window.confirm("Delete this college plan?")) return;
|
||
try {
|
||
const res = await authFetch(`/api/premium/college-profile/by-fields`, {
|
||
method: "DELETE",
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
career_title : row.career_title || null,
|
||
selected_school: row.selected_school || null,
|
||
selected_program: row.selected_program || null,
|
||
created_at : row.created_at || null // optional disambiguator
|
||
})
|
||
});
|
||
if (!res.ok) throw new Error(`delete failed → ${res.status}`);
|
||
setRows((r) => r.filter(x =>
|
||
!(
|
||
(x.career_title||'') === (row.career_title||'') &&
|
||
(x.selected_school||'') === (row.selected_school||'') &&
|
||
(x.selected_program||'')=== (row.selected_program||'') &&
|
||
(x.created_at||'') === (row.created_at||'')
|
||
)
|
||
));
|
||
if (!res.ok) throw new Error(`delete failed → ${res.status}`);
|
||
setRows((r) => r.filter(x =>
|
||
!(
|
||
(x.career_title||'') === (row.career_title||'') &&
|
||
(x.selected_school||'') === (row.selected_school||'') &&
|
||
(x.selected_program||'')=== (row.selected_program||'') &&
|
||
(x.created_at||'') === (row.created_at||'')
|
||
)
|
||
));
|
||
} catch (err) {
|
||
console.error("Delete failed:", err);
|
||
alert("Could not delete – see console.");
|
||
}
|
||
}
|
||
|
||
|
||
return (
|
||
<div className="max-w-5xl mx-auto space-y-6">
|
||
{/* ───────── header row ───────── */}
|
||
<div className="flex items-center justify-between">
|
||
<h2 className="text-2xl font-semibold">College Plans</h2>
|
||
|
||
{/* new‑plan button & inline picker */}
|
||
{!showPicker ? (
|
||
<button
|
||
onClick={() => setShowPicker(true)}
|
||
className="px-3 py-2 bg-blue-600 text-white rounded"
|
||
>
|
||
+ New College Plan
|
||
</button>
|
||
) : (
|
||
<div className="p-4 border rounded bg-gray-50 max-w-md">
|
||
<CareerSelectDropdown
|
||
existingCareerProfiles={careerRows}
|
||
selectedCareer={null}
|
||
loading={loadingCareers}
|
||
authFetch={authFetch}
|
||
onChange={(careerObj) => {
|
||
if (!careerObj) return;
|
||
const title = careerObj.scenario_title || careerObj.career_name || '';
|
||
const start = careerObj.start_date || '';
|
||
navigate(`/profile/college/new?career=${encodeURIComponent(title)}&start=${encodeURIComponent(start)}`);
|
||
}}
|
||
/>
|
||
<div className="mt-2 text-right">
|
||
<button
|
||
onClick={() => setShowPicker(false)}
|
||
className="text-sm text-gray-600 underline"
|
||
>
|
||
cancel
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* ───────── table of existing college plans ───────── */}
|
||
<table className="w-full border text-sm">
|
||
<thead className="bg-gray-100">
|
||
<tr>
|
||
<th className="p-2 text-left">Career</th>
|
||
<th className="p-2 text-left">School</th>
|
||
<th className="p-2 text-left">Program</th>
|
||
<th className="p-2">Created</th>
|
||
<th className="p-2"></th>
|
||
</tr>
|
||
</thead>
|
||
|
||
<tbody>
|
||
{rows.map((r) => (
|
||
<tr key={`${r.career_title}|${r.selected_school}|${r.selected_program}|${r.created_at}`} className="border-t">
|
||
<td className="p-2">{r.career_title}</td>
|
||
<td className="p-2">{r.selected_school}</td>
|
||
<td className="p-2">{r.selected_program}</td>
|
||
<td className="p-2">{r.created_at?.slice(0, 10)}</td>
|
||
<td className="p-2 space-x-2 whitespace-nowrap">
|
||
<Link
|
||
to={`/profile/college/${encodeURIComponent(r.career_profile_id)}/edit`}
|
||
className="underline text-blue-600"
|
||
>edit</Link>
|
||
<button
|
||
onClick={() => handleDelete(r)}
|
||
className="underline text-red-600"
|
||
>
|
||
delete
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
|
||
{rows.length === 0 && (
|
||
<tr>
|
||
<td colSpan={6} className="p-8 text-center text-gray-500">
|
||
No college profiles yet.
|
||
<button
|
||
className="text-blue-600 underline"
|
||
onClick={() =>
|
||
careerId
|
||
? navigate(`/profile/college/${careerId}/new`)
|
||
: setShowPicker(true)
|
||
}
|
||
>
|
||
Create one now.
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
);
|
||
}
|