shared.NewProject(field(fields, "name"), field(fields, "description"))
|> shared.new_project_json
#(
- model,
+ Model(..model, project_name: "", project_description: ""),
rsvp.post(
"/api/projects",
body,
)
|> shared.new_task_json
#(
- model,
+ Model(
+ ..model,
+ task_title: "",
+ task_description: "",
+ task_assignee: "",
+ task_assignees: "",
+ task_due_date: "",
+ ),
rsvp.post(
"/api/projects/" <> int.to_string(project_id) <> "/tasks",
body,
let status = field(fields, "status")
let body = shared.StatusChange(status) |> shared.status_change_json
#(
- model,
+ update_task_status(model, task_id, status),
rsvp.post(
"/api/tasks/" <> int.to_string(task_id) <> "/status",
body,
)
}
DeleteTask(task_id) -> #(
- model,
+ remove_task(model, task_id),
rsvp.delete(
"/api/tasks/" <> int.to_string(task_id),
json.object([]),
),
)
DeleteProject(project_id) -> #(
- model,
+ remove_project(model, project_id),
rsvp.delete(
"/api/projects/" <> int.to_string(project_id),
json.object([]),
}
}
+fn update_task_status(model: Model, task_id: Int, status: String) -> Model {
+ case model.dashboard {
+ None -> model
+ Some(board) -> {
+ let projects =
+ list.map(board.projects, fn(project) {
+ let tasks =
+ list.map(project.tasks, fn(task) {
+ case task.id == task_id {
+ True -> shared.Task(..task, status: status)
+ False -> task
+ }
+ })
+ shared.Project(..project, tasks: tasks)
+ })
+ Model(
+ ..model,
+ dashboard: Some(shared.Dashboard(..board, projects: projects)),
+ )
+ }
+ }
+}
+
+fn remove_task(model: Model, task_id: Int) -> Model {
+ case model.dashboard {
+ None -> model
+ Some(board) -> {
+ let projects =
+ list.map(board.projects, fn(project) {
+ let tasks =
+ list.filter(project.tasks, fn(task) { task.id != task_id })
+ shared.Project(..project, tasks: tasks)
+ })
+ Model(
+ ..model,
+ dashboard: Some(shared.Dashboard(..board, projects: projects)),
+ )
+ }
+ }
+}
+
+fn remove_project(model: Model, project_id: Int) -> Model {
+ case model.dashboard {
+ None -> model
+ Some(board) -> {
+ let projects =
+ list.filter(board.projects, fn(project) { project.id != project_id })
+ Model(
+ ..model,
+ dashboard: Some(shared.Dashboard(..board, projects: projects)),
+ )
+ }
+ }
+}
+
fn auth_request(
model: Model,
fields: List(#(String, String)),
fn view(model: Model) -> Element(Message) {
case model.page {
- "login" -> auth_view(model, "Welcome back", "Log in", LoginSubmitted)
+ "login" -> auth_view(model, "Greetings Comrade", "Log in", LoginSubmitted)
"register" ->
creat_account_view(
model,
- "Create your account",
+ "Create account",
"Create account",
RegisterSubmitted,
)
styles(),
html.text("FRC 972 · IRON CLAW"),
html.h1([], [html.text(title)]),
- html.p([], [html.text("google sheets, more like shmoogle shits")]),
+ html.p([], [
+ html.text(
+ "google sheets, more like shmoogle shits (also passwords need to be at least 8 chars and username needs to be at least 3)",
+ ),
+ ]),
error_view(model.error),
html.form([event.on_submit(on_submit)], [
html.input([
case model.dashboard {
None ->
html.main([attribute.class("auth")], [
- html.h1([], [html.text("Loading Iron Claw...")]),
+ html.h1([], [html.text("Loading Iron Claw")]),
error_view(model.error),
])
Some(board) ->
],
[
html.form(
- [event.on_submit(fn(fields) { TaskSubmitted(project.id, fields) })],
+ [
+ attribute.class("task-form"),
+ attribute.styles([
+ #("display", "grid"),
+ #("grid-template-columns", "repeat(4, minmax(0, 1fr))"),
+ #("align-items", "start"),
+ ]),
+ event.on_submit(fn(fields) { TaskSubmitted(project.id, fields) }),
+ ],
[
text_input("title", "Task title"),
text_input("assignee", "Owner"),
text_input("assignees", "Assignees"),
text_input("due_date", "Due (MM/DD/YY)"),
- text_input("description", "Details"),
- html.button([], [html.text("Add task")]),
+ html.textarea(
+ [
+ attribute.class("task-description-input"),
+ attribute.styles([
+ #("grid-column", "1 / -1"),
+ #("width", "100%"),
+ #("box-sizing", "border-box"),
+ #("min-height", "96px"),
+ #("resize", "vertical"),
+ #("padding", "12px 13px"),
+ #("border", "1px solid #d9cfc2"),
+ #("background", "#fffcf8"),
+ #("color", "#28231e"),
+ #("font", "inherit"),
+ ]),
+ attribute.name("description"),
+ attribute.placeholder("Details"),
+ attribute.rows(4),
+ ],
+ "",
+ ),
+ html.button([attribute.class("task-submit")], [
+ html.text("Add task"),
+ ]),
],
),
],
],
),
]),
- html.p([attribute.class("task-description")], [html.text(task.description)]),
+ html.p(
+ [
+ attribute.class("task-description"),
+ attribute.style("white-space", "pre-wrap"),
+ ],
+ [html.text(task.description)],
+ ),
html.div([attribute.class("task-details")], [
html.div([attribute.class("task-person")], [
html.small([], [html.text("Owner")]),
fn styles() -> Element(Message) {
html.style(
[],
- "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:#b53b24;font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:#b53b24;font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.kanban{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:22px}.kanban-column{background:#f7f3ed;border:1px solid #ebe1d4;padding:13px}.kanban-column h3{font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:#796f64;margin:0 0 5px}.task{display:flex;flex-direction:column;gap:13px;background:#fff;border:1px solid #e8dfd4;padding:16px;margin:9px 0;box-shadow:0 4px 12px #2d24140a;min-width:0}.task-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.task-title{font-size:1rem;line-height:1.25;overflow-wrap:anywhere}.delete-task{flex:0 0 auto;padding:5px 8px;font-size:.68rem;background:#f0ebe3;color:#796f64}.delete-task:hover{background:#e8dfd4;color:#28231e}.task-description{margin:0;color:#796f64;line-height:1.45;overflow-wrap:anywhere}.task-details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 14px;padding-top:12px;border-top:1px solid #eee6dc;color:#4e463e;font-size:.8rem}.task-person,.task-due{display:flex;flex-direction:column;gap:4px;min-width:0;overflow-wrap:anywhere}.task-details small{color:#a04a35;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-due{grid-column:1/-1}.task-footer{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:2px}.task-status{padding:5px 8px;background:#f0ebe3;color:#796f64;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-actions{display:flex;gap:6px;margin-left:auto}.task-actions form{margin:0}.move-task{width:31px;height:29px;padding:0;font-size:1.05rem;line-height:1}.move-task:hover{background:#902e1d}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;background:#fffcf8;color:#28231e;font:inherit}button{border:0;background:#b53b24;color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:#b53b24;font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:800px){.kanban{grid-template-columns:1fr 1fr}}@media(max-width:650px){.kanban{grid-template-columns:1fr}.task-details{grid-template-columns:1fr}.task-due{grid-column:auto}header{display:block}.hero{padding:28px}}",
+ "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:rgb(255, 100, 0);font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:rgb(255, 100, 0);font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.kanban{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:22px}.kanban-column{background:#f7f3ed;border:1px solid #ebe1d4;padding:13px}.kanban-column h3{font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:#796f64;margin:0 0 5px}.task{display:flex;flex-direction:column;gap:13px;background:#fff;border:1px solid #e8dfd4;padding:16px;margin:9px 0;box-shadow:0 4px 12px #2d24140a;min-width:0}.task-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.task-title{font-size:1rem;line-height:1.25;overflow-wrap:anywhere}.delete-task{flex:0 0 auto;padding:5px 8px;font-size:.68rem;background:#f0ebe3;color:#796f64}.delete-task:hover{background:#e8dfd4;color:#28231e}.task-description{margin:0;color:#796f64;line-height:1.45;overflow-wrap:anywhere}.task-details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 14px;padding-top:12px;border-top:1px solid #eee6dc;color:#4e463e;font-size:.8rem}.task-person,.task-due{display:flex;flex-direction:column;gap:4px;min-width:0;overflow-wrap:anywhere}.task-details small{color:#000000;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-due{grid-column:1/-1}.task-footer{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:2px}.task-status{padding:5px 8px;background:#f0ebe3;color:#796f64;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-actions{display:flex;gap:6px;margin-left:auto}.task-actions form{margin:0}.move-task{width:31px;height:29px;padding:0;font-size:1.05rem;line-height:1}.move-task:hover{background:#902e1d}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;background:#fffcf8;color:#28231e;font:inherit}button{border:0;background:rgb(255, 100, 0);color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:rgb(255, 100, 0);font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:800px){.kanban{grid-template-columns:1fr 1fr}}@media(max-width:650px){.kanban{grid-template-columns:1fr}.task-details{grid-template-columns:1fr}.task-due{grid-column:auto}header{display:block}.hero{padding:28px}}",
)
}
function attribute(name, value) {
return new Attribute(attribute_kind, name, value);
}
+function property(name, value) {
+ return new Property(property_kind, name, value);
+}
function event(name, handler, include, prevent_default, stop_propagation, debounce, throttle) {
return new Event2(event_kind, name, handler, include, prevent_default, stop_propagation, debounce, throttle);
}
function attribute2(name, value) {
return attribute(name, value);
}
+function property2(name, value) {
+ return property(name, value);
+}
function class$(name) {
return attribute2("class", name);
}
+function style(property3, value) {
+ if (property3 === "") {
+ return class$("");
+ } else if (value === "") {
+ return class$("");
+ } else {
+ return attribute2("style", property3 + ":" + value + ";");
+ }
+}
+function do_styles(loop$properties, loop$styles) {
+ while (true) {
+ let properties = loop$properties;
+ let styles = loop$styles;
+ if (properties instanceof Empty) {
+ return styles;
+ } else {
+ let $ = properties.head[0];
+ if ($ === "") {
+ let rest = properties.tail;
+ loop$properties = rest;
+ loop$styles = styles;
+ } else {
+ let $1 = properties.head[1];
+ if ($1 === "") {
+ let rest = properties.tail;
+ loop$properties = rest;
+ loop$styles = styles;
+ } else {
+ let rest = properties.tail;
+ let name$1 = $;
+ let value$1 = $1;
+ loop$properties = rest;
+ loop$styles = styles + name$1 + ":" + value$1 + ";";
+ }
+ }
+ }
+ }
+}
+function styles(properties) {
+ return attribute2("style", do_styles(properties, ""));
+}
function href(url) {
return attribute2("href", url);
}
function placeholder(text) {
return attribute2("placeholder", text);
}
+function rows(value) {
+ return attribute2("rows", to_string(value));
+}
function type_(control_type) {
return attribute2("type", control_type);
}
function text3(content) {
return text2(content);
}
-function style(attrs, css) {
+function style2(attrs, css) {
return unsafe_raw_html("", "style", attrs, css);
}
function article(attrs, children) {
function input(attrs) {
return element2("input", attrs, empty_list);
}
+function textarea(attrs, content) {
+ return element2("textarea", prepend(property2("value", string4(content)), attrs), toList([text2(content)]));
+}
// build/dev/javascript/lustre/lustre/vdom/patch.mjs
class Patch extends CustomType {
class$("delete-task")
]), toList([text3("Delete")]))
])),
- p(toList([class$("task-description")]), toList([text3(task.description)])),
+ p(toList([
+ class$("task-description"),
+ style("white-space", "pre-wrap")
+ ]), toList([text3(task.description)])),
div(toList([class$("task-details")]), toList([
div(toList([class$("task-person")]), toList([
small(List$Empty$const, toList([text3("Owner")])),
]))
]), toList([
form(toList([
+ class$("task-form"),
+ styles(toList([
+ ["display", "grid"],
+ ["grid-template-columns", "repeat(4, minmax(0, 1fr))"],
+ ["align-items", "start"]
+ ])),
on_submit((fields) => {
return new TaskSubmitted(project.id, fields);
})
text_input("assignee", "Owner"),
text_input("assignees", "Assignees"),
text_input("due_date", "Due (MM/DD/YY)"),
- text_input("description", "Details"),
- button(List$Empty$const, toList([text3("Add task")]))
+ textarea(toList([
+ class$("task-description-input"),
+ styles(toList([
+ ["grid-column", "1 / -1"],
+ ["width", "100%"],
+ ["box-sizing", "border-box"],
+ ["min-height", "96px"],
+ ["resize", "vertical"],
+ ["padding", "12px 13px"],
+ ["border", "1px solid #d9cfc2"],
+ ["background", "#fffcf8"],
+ ["color", "#28231e"],
+ ["font", "inherit"]
+ ])),
+ name("description"),
+ placeholder("Details"),
+ rows(4)
+ ]), ""),
+ button(toList([class$("task-submit")]), toList([text3("Add task")]))
]))
]))));
}
-function styles() {
- return style(List$Empty$const, "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:#b53b24;font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:#b53b24;font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.kanban{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:22px}.kanban-column{background:#f7f3ed;border:1px solid #ebe1d4;padding:13px}.kanban-column h3{font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:#796f64;margin:0 0 5px}.task{display:flex;flex-direction:column;gap:13px;background:#fff;border:1px solid #e8dfd4;padding:16px;margin:9px 0;box-shadow:0 4px 12px #2d24140a;min-width:0}.task-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.task-title{font-size:1rem;line-height:1.25;overflow-wrap:anywhere}.delete-task{flex:0 0 auto;padding:5px 8px;font-size:.68rem;background:#f0ebe3;color:#796f64}.delete-task:hover{background:#e8dfd4;color:#28231e}.task-description{margin:0;color:#796f64;line-height:1.45;overflow-wrap:anywhere}.task-details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 14px;padding-top:12px;border-top:1px solid #eee6dc;color:#4e463e;font-size:.8rem}.task-person,.task-due{display:flex;flex-direction:column;gap:4px;min-width:0;overflow-wrap:anywhere}.task-details small{color:#a04a35;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-due{grid-column:1/-1}.task-footer{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:2px}.task-status{padding:5px 8px;background:#f0ebe3;color:#796f64;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-actions{display:flex;gap:6px;margin-left:auto}.task-actions form{margin:0}.move-task{width:31px;height:29px;padding:0;font-size:1.05rem;line-height:1}.move-task:hover{background:#902e1d}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;background:#fffcf8;color:#28231e;font:inherit}button{border:0;background:#b53b24;color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:#b53b24;font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:800px){.kanban{grid-template-columns:1fr 1fr}}@media(max-width:650px){.kanban{grid-template-columns:1fr}.task-details{grid-template-columns:1fr}.task-due{grid-column:auto}header{display:block}.hero{padding:28px}}");
+function styles2() {
+ return style2(List$Empty$const, "body{margin:0;background:#f4f0e8;color:#28231e;font-family:Inter,ui-sans-serif,system-ui,sans-serif}.page{max-width:1120px;margin:auto;padding:28px 22px 72px}.auth{max-width:430px;margin:10vh auto;padding:42px;background:#fff;border:1px solid #e2d9cc;box-shadow:0 20px 60px #2d241414}.auth h1{font-size:clamp(2.4rem,8vw,4.8rem);line-height:.95;letter-spacing:-.06em;margin:14px 0}.auth form{display:grid;gap:12px;margin:26px 0 14px}.auth a{color:rgb(255, 100, 0);font-weight:700}.eyebrow{font-size:.72rem;letter-spacing:.16em;color:rgb(255, 100, 0);font-weight:800}header{display:flex;justify-content:space-between;gap:24px;align-items:start;margin-bottom:42px}header h1{font-size:clamp(2.7rem,7vw,5.5rem);line-height:.9;letter-spacing:-.07em;margin:12px 0}.hero{padding:42px;background:linear-gradient(120deg,#29241f,#594538);color:#fff;margin-bottom:20px;font-size:clamp(1.5rem,3vw,2.5rem);font-weight:800;letter-spacing:-.04em}.panel{background:#fff;border:1px solid #e2d9cc;padding:24px;margin:18px 0;box-shadow:0 12px 30px #2d24140b}.panel h2{margin:5px 0 8px;letter-spacing:-.03em}.panel>p{color:#796f64}.kanban{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:22px}.kanban-column{background:#f7f3ed;border:1px solid #ebe1d4;padding:13px}.kanban-column h3{font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:#796f64;margin:0 0 5px}.task{display:flex;flex-direction:column;gap:13px;background:#fff;border:1px solid #e8dfd4;padding:16px;margin:9px 0;box-shadow:0 4px 12px #2d24140a;min-width:0}.task-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.task-title{font-size:1rem;line-height:1.25;overflow-wrap:anywhere}.delete-task{flex:0 0 auto;padding:5px 8px;font-size:.68rem;background:#f0ebe3;color:#796f64}.delete-task:hover{background:#e8dfd4;color:#28231e}.task-description{margin:0;color:#796f64;line-height:1.45;overflow-wrap:anywhere}.task-details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 14px;padding-top:12px;border-top:1px solid #eee6dc;color:#4e463e;font-size:.8rem}.task-person,.task-due{display:flex;flex-direction:column;gap:4px;min-width:0;overflow-wrap:anywhere}.task-details small{color:#000000;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-due{grid-column:1/-1}.task-footer{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:2px}.task-status{padding:5px 8px;background:#f0ebe3;color:#796f64;font-size:.68rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.task-actions{display:flex;gap:6px;margin-left:auto}.task-actions form{margin:0}.move-task{width:31px;height:29px;padding:0;font-size:1.05rem;line-height:1}.move-task:hover{background:#902e1d}form{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}input{min-width:150px;flex:1;padding:12px 13px;border:1px solid #d9cfc2;background:#fffcf8;color:#28231e;font:inherit}button{border:0;background:rgb(255, 100, 0);color:#fff;padding:12px 17px;font:inherit;font-weight:800;cursor:pointer}button:hover{background:#902e1d}.error{color:rgb(255, 100, 0);font-weight:700}a{color:inherit;text-decoration:none}@media(max-width:800px){.kanban{grid-template-columns:1fr 1fr}}@media(max-width:650px){.kanban{grid-template-columns:1fr}.task-details{grid-template-columns:1fr}.task-due{grid-column:auto}header{display:block}.hero{padding:28px}}");
}
function error_view(error) {
if (error instanceof Some) {
if ($ instanceof Some) {
let board = $[0];
return main(toList([class$("page")]), append(toList([
- styles(),
+ styles2(),
header(List$Empty$const, toList([
div(List$Empty$const, toList([
text3("FRC 972 · IRON CLAW"),
})));
} else {
return main(toList([class$("auth")]), toList([
- h1(List$Empty$const, toList([text3("Loading Iron Claw...")])),
+ h1(List$Empty$const, toList([text3("Loading Iron Claw")])),
error_view(model.error)
]));
}
}
let link_text = _block$1;
return main(toList([class$("auth")]), toList([
- styles(),
+ styles2(),
text3("FRC 972 · IRON CLAW"),
h1(List$Empty$const, toList([text3(title2)])),
- p(List$Empty$const, toList([text3("google sheets, more like shmoogle shits")])),
+ p(List$Empty$const, toList([
+ text3("google sheets, more like shmoogle shits (also passwords need to be at least 8 chars and username needs to be at least 3)")
+ ])),
error_view(model.error),
form(toList([on_submit(on_submit2)]), toList([
input(toList([
}
let link_text = _block$1;
return main(toList([class$("auth")]), toList([
- styles(),
+ styles2(),
text3("Team 972 · IRON CLAW"),
h1(List$Empty$const, toList([text3(title2)])),
p(List$Empty$const, toList([text3("google sheets, more like shmoogle shits")])),
function view(model) {
let $ = model.page;
if ($ === "login") {
- return auth_view(model, "Welcome back", "Log in", (var0) => {
+ return auth_view(model, "Greetings Comrade", "Log in", (var0) => {
return new LoginSubmitted(var0);
});
} else if ($ === "register") {
- return creat_account_view(model, "Create your account", "Create account", (var0) => {
+ return creat_account_view(model, "Create account", "Create account", (var0) => {
return new RegisterSubmitted(var0);
});
} else {
return dashboard_view(model);
}
}
+function remove_project(model, project_id) {
+ let $ = model.dashboard;
+ if ($ instanceof Some) {
+ let board = $[0];
+ let projects = filter(board.projects, (project) => {
+ return project.id !== project_id;
+ });
+ return new Model(model.page, new Some(new Dashboard(board.username, projects)), model.error, model.username, model.password, model.invite_password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date);
+ } else {
+ return model;
+ }
+}
+function remove_task(model, task_id) {
+ let $ = model.dashboard;
+ if ($ instanceof Some) {
+ let board = $[0];
+ let projects = map2(board.projects, (project) => {
+ let tasks = filter(project.tasks, (task) => {
+ return task.id !== task_id;
+ });
+ return new Project(project.id, project.name, project.description, tasks);
+ });
+ return new Model(model.page, new Some(new Dashboard(board.username, projects)), model.error, model.username, model.password, model.invite_password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date);
+ } else {
+ return model;
+ }
+}
+function update_task_status(model, task_id, status) {
+ let $ = model.dashboard;
+ if ($ instanceof Some) {
+ let board = $[0];
+ let projects = map2(board.projects, (project) => {
+ let tasks = map2(project.tasks, (task) => {
+ let $1 = task.id === task_id;
+ if ($1) {
+ return new Task(task.id, task.project_id, task.title, task.description, status, task.assignee, task.assignees, task.due_date);
+ } else {
+ return task;
+ }
+ });
+ return new Project(project.id, project.name, project.description, tasks);
+ });
+ return new Model(model.page, new Some(new Dashboard(board.username, projects)), model.error, model.username, model.password, model.invite_password, model.project_name, model.project_description, model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date);
+ } else {
+ return model;
+ }
+}
function field2(fields, name2) {
let _pipe = key_find(fields, name2);
return unwrap2(_pipe, "");
_block = new_project_json(_pipe);
let body2 = _block;
return [
- model,
+ new Model(model.page, model.dashboard, model.error, model.username, model.password, model.invite_password, "", "", model.task_title, model.task_description, model.task_assignee, model.task_assignees, model.task_due_date),
post("/api/projects", body2, expect_any_response((result) => {
return new Saved((() => {
let _pipe$1 = result;
_block = new_task_json(_pipe);
let body2 = _block;
return [
- model,
+ new Model(model.page, model.dashboard, model.error, model.username, model.password, model.invite_password, model.project_name, model.project_description, "", "", "", "", ""),
post("/api/projects/" + to_string(project_id) + "/tasks", body2, expect_any_response((result) => {
return new Saved((() => {
let _pipe$1 = result;
_block = status_change_json(_pipe);
let body2 = _block;
return [
- model,
+ update_task_status(model, task_id, status),
post("/api/tasks/" + to_string(task_id) + "/status", body2, expect_any_response((result) => {
return new Saved((() => {
let _pipe$1 = result;
} else if (message2 instanceof DeleteTask) {
let task_id = message2[0];
return [
- model,
+ remove_task(model, task_id),
delete$2("/api/tasks/" + to_string(task_id), object2(List$Empty$const), expect_any_response((result) => {
return new Saved((() => {
let _pipe = result;
} else if (message2 instanceof DeleteProject) {
let project_id = message2[0];
return [
- model,
+ remove_project(model, project_id),
delete$2("/api/projects/" + to_string(project_id), object2(List$Empty$const), expect_any_response((result) => {
return new Saved((() => {
let _pipe = result;