feat(frontend): weekly grid editor with day tabs and copy shortcut
This commit is contained in:
@@ -9,7 +9,9 @@ import type {
|
||||
ProgrammingBlock,
|
||||
MediaFilter,
|
||||
RecyclePolicy,
|
||||
Weekday,
|
||||
} from "@/lib/types";
|
||||
import { WEEKDAYS } from "@/lib/types";
|
||||
|
||||
export const WEBHOOK_PRESETS = {
|
||||
discord: `{
|
||||
@@ -54,11 +56,17 @@ export function defaultBlock(startMins = 20 * 60, durationMins = 60): Programmin
|
||||
};
|
||||
}
|
||||
|
||||
function emptyDayBlocks(): Record<Weekday, ProgrammingBlock[]> {
|
||||
const result = {} as Record<Weekday, ProgrammingBlock[]>;
|
||||
for (const d of WEEKDAYS) result[d] = [];
|
||||
return result;
|
||||
}
|
||||
|
||||
export function useChannelForm(channel: ChannelResponse | null) {
|
||||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [timezone, setTimezone] = useState("UTC");
|
||||
const [blocks, setBlocks] = useState<ProgrammingBlock[]>([]);
|
||||
const [dayBlocks, setDayBlocks] = useState<Record<Weekday, ProgrammingBlock[]>>(emptyDayBlocks);
|
||||
const [recyclePolicy, setRecyclePolicy] = useState<RecyclePolicy>({
|
||||
cooldown_days: null,
|
||||
cooldown_generations: null,
|
||||
@@ -84,7 +92,10 @@ export function useChannelForm(channel: ChannelResponse | null) {
|
||||
setName(channel.name);
|
||||
setDescription(channel.description ?? "");
|
||||
setTimezone(channel.timezone);
|
||||
setBlocks(channel.schedule_config.day_blocks['monday'] ?? []);
|
||||
setDayBlocks({
|
||||
...emptyDayBlocks(),
|
||||
...channel.schedule_config.day_blocks,
|
||||
});
|
||||
setRecyclePolicy(channel.recycle_policy);
|
||||
setAutoSchedule(channel.auto_schedule);
|
||||
setAccessMode(channel.access_mode ?? "public");
|
||||
@@ -110,20 +121,23 @@ export function useChannelForm(channel: ChannelResponse | null) {
|
||||
}
|
||||
}, [channel]);
|
||||
|
||||
const addBlock = (startMins = 20 * 60, durationMins = 60) => {
|
||||
const addBlock = (day: Weekday, startMins = 20 * 60, durationMins = 60) => {
|
||||
const block = defaultBlock(startMins, durationMins);
|
||||
setBlocks((prev) => [...prev, block]);
|
||||
setDayBlocks((prev) => ({ ...prev, [day]: [...(prev[day] ?? []), block] }));
|
||||
setSelectedBlockId(block.id);
|
||||
};
|
||||
|
||||
const updateBlock = (idx: number, block: ProgrammingBlock) =>
|
||||
setBlocks((prev) => prev.map((b, i) => (i === idx ? block : b)));
|
||||
const updateBlock = (day: Weekday, idx: number, block: ProgrammingBlock) =>
|
||||
setDayBlocks((prev) => ({
|
||||
...prev,
|
||||
[day]: (prev[day] ?? []).map((b, i) => (i === idx ? block : b)),
|
||||
}));
|
||||
|
||||
const removeBlock = (idx: number) => {
|
||||
setBlocks((prev) => {
|
||||
const next = prev.filter((_, i) => i !== idx);
|
||||
if (selectedBlockId === prev[idx].id) setSelectedBlockId(null);
|
||||
return next;
|
||||
const removeBlock = (day: Weekday, idx: number) => {
|
||||
setDayBlocks((prev) => {
|
||||
const dayArr = prev[day] ?? [];
|
||||
if (selectedBlockId === dayArr[idx]?.id) setSelectedBlockId(null);
|
||||
return { ...prev, [day]: dayArr.filter((_, i) => i !== idx) };
|
||||
});
|
||||
};
|
||||
|
||||
@@ -147,8 +161,8 @@ export function useChannelForm(channel: ChannelResponse | null) {
|
||||
webhookFormat, setWebhookFormat,
|
||||
webhookBodyTemplate, setWebhookBodyTemplate,
|
||||
webhookHeaders, setWebhookHeaders,
|
||||
// Blocks
|
||||
blocks, setBlocks,
|
||||
// Blocks (day-keyed)
|
||||
dayBlocks, setDayBlocks,
|
||||
selectedBlockId, setSelectedBlockId,
|
||||
recyclePolicy, setRecyclePolicy,
|
||||
addBlock,
|
||||
|
||||
Reference in New Issue
Block a user