This commit is contained in:
@@ -65,6 +65,7 @@ interface ShotStatusClientProps {
|
|||||||
selectedProjectId: string | null;
|
selectedProjectId: string | null;
|
||||||
selectedProject: Project | null;
|
selectedProject: Project | null;
|
||||||
shots: ShotRow[];
|
shots: ShotRow[];
|
||||||
|
episodeDueDates: { episode: string; dueDate: Date | string }[];
|
||||||
canManage: boolean;
|
canManage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,11 +389,23 @@ export function ShotStatusClient({
|
|||||||
selectedProjectId,
|
selectedProjectId,
|
||||||
selectedProject,
|
selectedProject,
|
||||||
shots,
|
shots,
|
||||||
|
episodeDueDates,
|
||||||
canManage,
|
canManage,
|
||||||
}: ShotStatusClientProps) {
|
}: ShotStatusClientProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
// Restore last selected project if no project is currently selected
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedProjectId) {
|
||||||
|
const saved = localStorage.getItem("shotStatus:lastProjectId");
|
||||||
|
if (saved && projects.some((p) => p.id === saved)) {
|
||||||
|
router.replace(`/shot-status?projectId=${saved}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const [collapsedEpisodes, setCollapsedEpisodes] = useState<Set<string>>(new Set());
|
const [collapsedEpisodes, setCollapsedEpisodes] = useState<Set<string>>(new Set());
|
||||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||||
const [dueDateDialogOpen, setDueDateDialogOpen] = useState(false);
|
const [dueDateDialogOpen, setDueDateDialogOpen] = useState(false);
|
||||||
@@ -405,6 +418,7 @@ export function ShotStatusClient({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleProjectChange = (id: string) => {
|
const handleProjectChange = (id: string) => {
|
||||||
|
localStorage.setItem("shotStatus:lastProjectId", id);
|
||||||
setSelectedIds(new Set());
|
setSelectedIds(new Set());
|
||||||
router.push(`/shot-status?projectId=${id}`);
|
router.push(`/shot-status?projectId=${id}`);
|
||||||
};
|
};
|
||||||
@@ -454,6 +468,10 @@ export function ShotStatusClient({
|
|||||||
})()
|
})()
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
const episodeDueDateMap = new Map(
|
||||||
|
episodeDueDates.map((e) => [e.episode, new Date(e.dueDate)])
|
||||||
|
);
|
||||||
|
|
||||||
const statusCounts = shots.reduce(
|
const statusCounts = shots.reduce(
|
||||||
(acc, s) => {
|
(acc, s) => {
|
||||||
acc[s.status] = (acc[s.status] ?? 0) + 1;
|
acc[s.status] = (acc[s.status] ?? 0) + 1;
|
||||||
@@ -557,6 +575,8 @@ export function ShotStatusClient({
|
|||||||
const episodeIds = episodeShots.map((s) => s.id);
|
const episodeIds = episodeShots.map((s) => s.id);
|
||||||
const allEpSelected = episodeIds.every((id) => selectedIds.has(id));
|
const allEpSelected = episodeIds.every((id) => selectedIds.has(id));
|
||||||
const someEpSelected = episodeIds.some((id) => selectedIds.has(id));
|
const someEpSelected = episodeIds.some((id) => selectedIds.has(id));
|
||||||
|
const epDueDate = episodeDueDateMap.get(episode);
|
||||||
|
const epIsOverdue = epDueDate && epDueDate < new Date();
|
||||||
return (
|
return (
|
||||||
<div key={episode}>
|
<div key={episode}>
|
||||||
<div className="flex items-center gap-2 px-4 py-3 bg-zinc-800/60 hover:bg-zinc-800/90 transition-colors">
|
<div className="flex items-center gap-2 px-4 py-3 bg-zinc-800/60 hover:bg-zinc-800/90 transition-colors">
|
||||||
@@ -581,6 +601,15 @@ export function ShotStatusClient({
|
|||||||
<span className="text-xs text-zinc-500 font-normal">
|
<span className="text-xs text-zinc-500 font-normal">
|
||||||
{episodeShots.length} shot{episodeShots.length !== 1 ? "s" : ""}
|
{episodeShots.length} shot{episodeShots.length !== 1 ? "s" : ""}
|
||||||
</span>
|
</span>
|
||||||
|
{epDueDate && (
|
||||||
|
<span className={cn(
|
||||||
|
"flex items-center gap-1 text-xs",
|
||||||
|
epIsOverdue ? "text-red-400" : "text-zinc-400"
|
||||||
|
)}>
|
||||||
|
<Calendar className="h-3 w-3" />
|
||||||
|
{format(epDueDate, "d MMM yyyy")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ async function getProjects() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getEpisodeDueDatesForProject(projectId: string) {
|
||||||
|
return db.episodeDueDate.findMany({
|
||||||
|
where: { projectId },
|
||||||
|
select: { episode: true, dueDate: true },
|
||||||
|
orderBy: { episode: "asc" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function getShotsForProject(projectId: string) {
|
async function getShotsForProject(projectId: string) {
|
||||||
return db.shot.findMany({
|
return db.shot.findMany({
|
||||||
where: { projectId },
|
where: { projectId },
|
||||||
@@ -47,9 +55,10 @@ export default async function ShotStatusPage({
|
|||||||
const { projectId } = await searchParams;
|
const { projectId } = await searchParams;
|
||||||
const canManage = ["ADMIN", "PRODUCER", "SUPERVISOR"].includes(session.user.role);
|
const canManage = ["ADMIN", "PRODUCER", "SUPERVISOR"].includes(session.user.role);
|
||||||
|
|
||||||
const [projects, shots] = await Promise.all([
|
const [projects, shots, episodeDueDates] = await Promise.all([
|
||||||
getProjects(),
|
getProjects(),
|
||||||
projectId ? getShotsForProject(projectId) : Promise.resolve([]),
|
projectId ? getShotsForProject(projectId) : Promise.resolve([]),
|
||||||
|
projectId ? getEpisodeDueDatesForProject(projectId) : Promise.resolve([]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const selectedProject = projects.find((p) => p.id === projectId) ?? null;
|
const selectedProject = projects.find((p) => p.id === projectId) ?? null;
|
||||||
@@ -60,6 +69,7 @@ export default async function ShotStatusPage({
|
|||||||
selectedProjectId={projectId ?? null}
|
selectedProjectId={projectId ?? null}
|
||||||
selectedProject={selectedProject}
|
selectedProject={selectedProject}
|
||||||
shots={shots as any}
|
shots={shots as any}
|
||||||
|
episodeDueDates={episodeDueDates}
|
||||||
canManage={canManage}
|
canManage={canManage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user