Skip to content

Commit f07d824

Browse files
Blade/issue template (#432)
1 parent 2a698f4 commit f07d824

8 files changed

Lines changed: 2356 additions & 1049 deletions

File tree

apps/blade/src/app/_components/issues/create-edit-dialog.tsx

Lines changed: 624 additions & 1019 deletions
Large diffs are not rendered by default.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { EVENTS, ISSUE } from "@forge/consts";
2+
3+
export function defaultEventForm(): ISSUE.EventFormValues {
4+
return {
5+
discordId: "",
6+
googleId: "",
7+
name: "",
8+
tag: EVENTS.EVENT_TAGS[0],
9+
description: "",
10+
startDate: "",
11+
startTime: "",
12+
endDate: "",
13+
endTime: "",
14+
location: "",
15+
roles: [],
16+
dues_paying: false,
17+
isOperationsCalendar: false,
18+
discordChannelId: "",
19+
points: undefined,
20+
hackathonId: undefined,
21+
};
22+
}
23+
24+
export function getStatusLabel(status: string) {
25+
return status
26+
.toLowerCase()
27+
.replace(/_/g, " ")
28+
.replace(/\b\w/g, (char) => char.toUpperCase());
29+
}
30+
31+
export function normalizeTaskDueDate(dateValue?: string | Date) {
32+
const dueDate = dateValue ? new Date(dateValue) : new Date();
33+
if (Number.isNaN(dueDate.getTime())) {
34+
const fallback = new Date();
35+
fallback.setHours(ISSUE.TASK_DUE_HOURS, ISSUE.TASK_DUE_MINUTES, 0, 0);
36+
return fallback;
37+
}
38+
39+
dueDate.setHours(ISSUE.TASK_DUE_HOURS, ISSUE.TASK_DUE_MINUTES, 0, 0);
40+
return dueDate;
41+
}
42+
43+
export function getTaskDueDateInputValue(dateValue: Date | undefined) {
44+
if (!dateValue) return "";
45+
return normalizeTaskDueDate(dateValue).toISOString().slice(0, 10);
46+
}
47+
48+
export function parseTimeTo12h(timeValue?: string): {
49+
hour: string;
50+
minute: string;
51+
amPm: (typeof ISSUE.EVENT_TIME_AM_PM_OPTIONS)[number];
52+
} {
53+
const [hRaw, mRaw] = (timeValue ?? "").split(":");
54+
const h = Number(hRaw);
55+
const m = Number(mRaw);
56+
57+
if (Number.isNaN(h) || Number.isNaN(m)) {
58+
return {
59+
hour: "",
60+
minute: "",
61+
amPm: "PM" as (typeof ISSUE.EVENT_TIME_AM_PM_OPTIONS)[number],
62+
};
63+
}
64+
65+
const amPm: (typeof ISSUE.EVENT_TIME_AM_PM_OPTIONS)[number] =
66+
h >= 12 ? "PM" : "AM";
67+
const hour24 = h % 12 || 12;
68+
return {
69+
hour: hour24.toString().padStart(2, "0"),
70+
minute: m.toString().padStart(2, "0"),
71+
amPm,
72+
};
73+
}
74+
75+
export function to24h(
76+
hour12: string,
77+
amPm: (typeof ISSUE.EVENT_TIME_AM_PM_OPTIONS)[number],
78+
) {
79+
let h = Number(hour12);
80+
if (Number.isNaN(h)) {
81+
h = 0;
82+
}
83+
if (amPm === "PM" && h < 12) {
84+
h += 12;
85+
}
86+
if (amPm === "AM" && h === 12) {
87+
h = 0;
88+
}
89+
return h.toString().padStart(2, "0");
90+
}
91+
92+
export function toAmPmValue(
93+
value: string,
94+
): (typeof ISSUE.EVENT_TIME_AM_PM_OPTIONS)[number] {
95+
return value === "AM" ? "AM" : "PM";
96+
}
97+
98+
export function parseEventDateTime(dateValue?: string, timeValue?: string) {
99+
if (!dateValue || !timeValue) {
100+
return null;
101+
}
102+
103+
const [year, month, day] = dateValue.split("-").map(Number);
104+
const [hour, minute] = timeValue.split(":").map(Number);
105+
if (!year || !month || !day || Number.isNaN(hour) || Number.isNaN(minute)) {
106+
return null;
107+
}
108+
109+
const parsed = new Date(year, month - 1, day, hour, minute, 0, 0);
110+
if (Number.isNaN(parsed.getTime())) {
111+
return null;
112+
}
113+
114+
return parsed;
115+
}
116+
117+
// ─── Generic tree helpers ─────────────────────────────────────────────────────
118+
119+
export function updateTreeNode<T extends { children: T[] }>(
120+
nodes: T[],
121+
id: string,
122+
patch: Partial<T>,
123+
getId: (n: T) => string,
124+
): T[] {
125+
return nodes.map((n) => {
126+
if (getId(n) === id) return { ...n, ...patch };
127+
return { ...n, children: updateTreeNode(n.children, id, patch, getId) };
128+
});
129+
}
130+
131+
export function removeTreeNode<T extends { children: T[] }>(
132+
nodes: T[],
133+
id: string,
134+
getId: (n: T) => string,
135+
): T[] {
136+
return nodes
137+
.filter((n) => getId(n) !== id)
138+
.map((n) => ({ ...n, children: removeTreeNode(n.children, id, getId) }));
139+
}
140+
141+
export function addChildToTreeNode<T extends { children: T[] }>(
142+
nodes: T[],
143+
parentId: string,
144+
newChild: T,
145+
getId: (n: T) => string,
146+
): T[] {
147+
return nodes.map((n) => {
148+
if (getId(n) === parentId)
149+
return { ...n, children: [...n.children, newChild] };
150+
return {
151+
...n,
152+
children: addChildToTreeNode(n.children, parentId, newChild, getId),
153+
};
154+
});
155+
}

0 commit comments

Comments
 (0)