feat(frontend): support new fields
This commit is contained in:
parent
b41ca0b753
commit
66a0830ef2
|
@ -12,19 +12,12 @@ import Card from "./Card";
|
||||||
import TextInput from "./TextInput";
|
import TextInput from "./TextInput";
|
||||||
import Button, { ButtonStyle } from "./Button";
|
import Button, { ButtonStyle } from "./Button";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { WordStatus } from "../lib/api-fetch";
|
||||||
|
|
||||||
export interface EditField {
|
export interface EditField {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
pronouns: Record<string, PronounChoice>;
|
values: Array<{ value: string; status: WordStatus }>;
|
||||||
}
|
|
||||||
|
|
||||||
export enum PronounChoice {
|
|
||||||
favourite,
|
|
||||||
okay,
|
|
||||||
jokingly,
|
|
||||||
friendsOnly,
|
|
||||||
avoid,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditableCardProps = {
|
type EditableCardProps = {
|
||||||
|
@ -32,15 +25,15 @@ type EditableCardProps = {
|
||||||
onChangeName: React.ChangeEventHandler<HTMLInputElement>;
|
onChangeName: React.ChangeEventHandler<HTMLInputElement>;
|
||||||
onChangePronoun: React.ChangeEventHandler<HTMLInputElement>;
|
onChangePronoun: React.ChangeEventHandler<HTMLInputElement>;
|
||||||
onAddPronoun(pronoun: string): void;
|
onAddPronoun(pronoun: string): void;
|
||||||
onDeletePronoun(e: React.MouseEvent<HTMLButtonElement>, entry: string): void;
|
onDeletePronoun(e: React.MouseEvent<HTMLButtonElement>, index: number): void;
|
||||||
onChangeFavourite(
|
onChangeFavourite(
|
||||||
e: React.MouseEvent<HTMLButtonElement>,
|
e: React.MouseEvent<HTMLButtonElement>,
|
||||||
entry: string
|
index: number
|
||||||
): void;
|
): void;
|
||||||
onChangeOkay(e: React.MouseEvent<HTMLButtonElement>, entry: string): void;
|
onChangeOkay(e: React.MouseEvent<HTMLButtonElement>, index: number): void;
|
||||||
onChangeJokingly(e: React.MouseEvent<HTMLButtonElement>, entry: string): void;
|
onChangeJokingly(e: React.MouseEvent<HTMLButtonElement>, index: number): void;
|
||||||
onChangeFriends(e: React.MouseEvent<HTMLButtonElement>, entry: string): void;
|
onChangeFriends(e: React.MouseEvent<HTMLButtonElement>, index: number): void;
|
||||||
onChangeAvoid(e: React.MouseEvent<HTMLButtonElement>, entry: string): void;
|
onChangeAvoid(e: React.MouseEvent<HTMLButtonElement>, index: number): void;
|
||||||
onClickDelete: React.MouseEventHandler<HTMLButtonElement>;
|
onClickDelete: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,21 +69,20 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
return (
|
return (
|
||||||
<Card title={props.field.name} draggable footer={footer}>
|
<Card title={props.field.name} draggable footer={footer}>
|
||||||
<ul>
|
<ul>
|
||||||
{Object.keys(props.field.pronouns).map((pronoun, index) => {
|
{props.field.values.map((value, index) => {
|
||||||
const choice = props.field.pronouns[pronoun];
|
|
||||||
return (
|
return (
|
||||||
<li className="flex justify-between my-1 items-center" key={index}>
|
<li className="flex justify-between my-1 items-center" key={index}>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={pronoun}
|
value={value.value}
|
||||||
prevValue={pronoun}
|
prevValue={value.value}
|
||||||
onChange={props.onChangePronoun}
|
onChange={props.onChangePronoun}
|
||||||
/>
|
/>
|
||||||
<div className="rounded-md">
|
<div className="rounded-md">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onChangeFavourite(e, pronoun)}
|
onClick={(e) => props.onChangeFavourite(e, index)}
|
||||||
className={`${
|
className={`${
|
||||||
choice == PronounChoice.favourite
|
value.status == WordStatus.Favourite
|
||||||
? "bg-slate-500"
|
? "bg-slate-500"
|
||||||
: "bg-slate-600"
|
: "bg-slate-600"
|
||||||
} text-white hover:bg-slate-400 p-2`}
|
} text-white hover:bg-slate-400 p-2`}
|
||||||
|
@ -99,9 +91,9 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onChangeOkay(e, pronoun)}
|
onClick={(e) => props.onChangeOkay(e, index)}
|
||||||
className={`${
|
className={`${
|
||||||
choice == PronounChoice.okay
|
value.status == WordStatus.Okay
|
||||||
? "bg-slate-500"
|
? "bg-slate-500"
|
||||||
: "bg-slate-600"
|
: "bg-slate-600"
|
||||||
} text-white hover:bg-slate-400 p-2`}
|
} text-white hover:bg-slate-400 p-2`}
|
||||||
|
@ -110,9 +102,9 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onChangeJokingly(e, pronoun)}
|
onClick={(e) => props.onChangeJokingly(e, index)}
|
||||||
className={`${
|
className={`${
|
||||||
choice == PronounChoice.jokingly
|
value.status == WordStatus.Jokingly
|
||||||
? "bg-slate-500"
|
? "bg-slate-500"
|
||||||
: "bg-slate-600"
|
: "bg-slate-600"
|
||||||
} text-white hover:bg-slate-400 p-2`}
|
} text-white hover:bg-slate-400 p-2`}
|
||||||
|
@ -121,9 +113,9 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onChangeFriends(e, pronoun)}
|
onClick={(e) => props.onChangeFriends(e, index)}
|
||||||
className={`${
|
className={`${
|
||||||
choice == PronounChoice.friendsOnly
|
value.status == WordStatus.FriendsOnly
|
||||||
? "bg-slate-500"
|
? "bg-slate-500"
|
||||||
: "bg-slate-600"
|
: "bg-slate-600"
|
||||||
} text-white hover:bg-slate-400 p-2`}
|
} text-white hover:bg-slate-400 p-2`}
|
||||||
|
@ -132,9 +124,9 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onChangeAvoid(e, pronoun)}
|
onClick={(e) => props.onChangeAvoid(e, index)}
|
||||||
className={`${
|
className={`${
|
||||||
choice == PronounChoice.avoid
|
value.status == WordStatus.Avoid
|
||||||
? "bg-slate-500"
|
? "bg-slate-500"
|
||||||
: "bg-slate-600"
|
: "bg-slate-600"
|
||||||
} text-white hover:bg-slate-400 p-2`}
|
} text-white hover:bg-slate-400 p-2`}
|
||||||
|
@ -143,7 +135,7 @@ export function EditableCard(props: EditableCardProps) {
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => props.onDeletePronoun(e, pronoun)}
|
onClick={(e) => props.onDeletePronoun(e, index)}
|
||||||
className="bg-red-600 dark:bg-red-700 hover:bg-red-700 hover:dark:bg-red-800 p-2"
|
className="bg-red-600 dark:bg-red-700 hover:bg-red-700 hover:dark:bg-red-800 p-2"
|
||||||
>
|
>
|
||||||
<Trash3 />
|
<Trash3 />
|
||||||
|
|
|
@ -10,13 +10,9 @@ import { ReactSortable } from "react-sortablejs";
|
||||||
import { useRecoilState, useRecoilValue } from "recoil";
|
import { useRecoilState, useRecoilValue } from "recoil";
|
||||||
|
|
||||||
import Button, { ButtonStyle } from "../../components/Button";
|
import Button, { ButtonStyle } from "../../components/Button";
|
||||||
import {
|
import { EditableCard, EditField } from "../../components/Editable";
|
||||||
EditableCard,
|
|
||||||
EditField,
|
|
||||||
PronounChoice,
|
|
||||||
} from "../../components/Editable";
|
|
||||||
import Loading from "../../components/Loading";
|
import Loading from "../../components/Loading";
|
||||||
import { fetchAPI, Field, MeUser } from "../../lib/api-fetch";
|
import { fetchAPI, Field, MeUser, WordStatus } from "../../lib/api-fetch";
|
||||||
import { themeState, userState } from "../../lib/state";
|
import { themeState, userState } from "../../lib/state";
|
||||||
import toast from "../../lib/toast";
|
import toast from "../../lib/toast";
|
||||||
|
|
||||||
|
@ -31,23 +27,11 @@ export default function Index() {
|
||||||
const field: EditField = {
|
const field: EditField = {
|
||||||
id: i,
|
id: i,
|
||||||
name: f.name,
|
name: f.name,
|
||||||
pronouns: {},
|
values: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
f.favourite?.forEach((val) => {
|
f.entries?.forEach((entry) => {
|
||||||
field.pronouns[val] = PronounChoice.favourite;
|
field.values.push(entry);
|
||||||
});
|
|
||||||
f.okay?.forEach((val) => {
|
|
||||||
field.pronouns[val] = PronounChoice.okay;
|
|
||||||
});
|
|
||||||
f.jokingly?.forEach((val) => {
|
|
||||||
field.pronouns[val] = PronounChoice.jokingly;
|
|
||||||
});
|
|
||||||
f.friends_only?.forEach((val) => {
|
|
||||||
field.pronouns[val] = PronounChoice.friendsOnly;
|
|
||||||
});
|
|
||||||
f.avoid?.forEach((val) => {
|
|
||||||
field.pronouns[val] = PronounChoice.avoid;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return field;
|
return field;
|
||||||
|
@ -67,7 +51,7 @@ export default function Index() {
|
||||||
|
|
||||||
setFields([
|
setFields([
|
||||||
...fields,
|
...fields,
|
||||||
{ id: lastId + 1, name: `Field #${lastId + 2}`, pronouns: {} },
|
{ id: lastId + 1, name: `Field #${lastId + 2}`, values: [] },
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,43 +160,43 @@ export default function Index() {
|
||||||
e.target.attributes.getNamedItem("data-prev-value")?.value;
|
e.target.attributes.getNamedItem("data-prev-value")?.value;
|
||||||
if (!prev || !e.target.value) return;
|
if (!prev || !e.target.value) return;
|
||||||
|
|
||||||
const choice = field.pronouns[prev];
|
const idx = field.values.findIndex((val) => val.value === prev);
|
||||||
delete field.pronouns[prev];
|
if (idx !== -1) {
|
||||||
|
field.values[idx].value = e.target.value;
|
||||||
field.pronouns[e.target.value] = choice;
|
}
|
||||||
|
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onAddPronoun={(pronoun) => {
|
onAddPronoun={(pronoun) => {
|
||||||
field.pronouns[pronoun] = PronounChoice.okay;
|
field.values.push({ value: pronoun, status: WordStatus.Okay });
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onDeletePronoun={(e, pronoun) => {
|
onDeletePronoun={(e, index) => {
|
||||||
delete field.pronouns[pronoun];
|
delete field.values[index];
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeName={(e) => {
|
onChangeName={(e) => {
|
||||||
field.name = e.target.value;
|
field.name = e.target.value;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeFavourite={(e, entry: string) => {
|
onChangeFavourite={(e, index) => {
|
||||||
field.pronouns[entry] = PronounChoice.favourite;
|
field.values[index].status = WordStatus.Favourite;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeOkay={(e, entry: string) => {
|
onChangeOkay={(e, index) => {
|
||||||
field.pronouns[entry] = PronounChoice.okay;
|
field.values[index].status = WordStatus.Okay;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeJokingly={(e, entry: string) => {
|
onChangeJokingly={(e, index) => {
|
||||||
field.pronouns[entry] = PronounChoice.jokingly;
|
field.values[index].status = WordStatus.Jokingly;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeFriends={(e, entry: string) => {
|
onChangeFriends={(e, index) => {
|
||||||
field.pronouns[entry] = PronounChoice.friendsOnly;
|
field.values[index].status = WordStatus.FriendsOnly;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onChangeAvoid={(e, entry: string) => {
|
onChangeAvoid={(e, index) => {
|
||||||
field.pronouns[entry] = PronounChoice.avoid;
|
field.values[index].status = WordStatus.Avoid;
|
||||||
setFields([...fields]);
|
setFields([...fields]);
|
||||||
}}
|
}}
|
||||||
onClickDelete={(_) => {
|
onClickDelete={(_) => {
|
||||||
|
@ -233,8 +217,10 @@ function fieldsEqual(arr1: EditField[], arr2: EditField[]) {
|
||||||
if (!arr1.every((_, i) => arr1[i].id === arr2[i].id)) return false;
|
if (!arr1.every((_, i) => arr1[i].id === arr2[i].id)) return false;
|
||||||
|
|
||||||
return arr1.every((_, i) =>
|
return arr1.every((_, i) =>
|
||||||
Object.keys(arr1[i].pronouns).every(
|
arr1[i].values.every(
|
||||||
(val) => arr1[i].pronouns[val] === arr2[i].pronouns[val]
|
(val, j) =>
|
||||||
|
val.value === arr2[i].values[j].value &&
|
||||||
|
val.status === arr2[i].values[j].status
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -247,32 +233,10 @@ async function updateUser(args: {
|
||||||
const newFields = args.fields.map((editField) => {
|
const newFields = args.fields.map((editField) => {
|
||||||
const field: Field = {
|
const field: Field = {
|
||||||
name: editField.name,
|
name: editField.name,
|
||||||
favourite: [],
|
entries: [],
|
||||||
okay: [],
|
|
||||||
jokingly: [],
|
|
||||||
friends_only: [],
|
|
||||||
avoid: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(editField.pronouns).forEach((pronoun) => {
|
field.entries = [...editField.values];
|
||||||
switch (editField.pronouns[pronoun]) {
|
|
||||||
case PronounChoice.favourite:
|
|
||||||
field.favourite!.push(pronoun);
|
|
||||||
break;
|
|
||||||
case PronounChoice.okay:
|
|
||||||
field.okay!.push(pronoun);
|
|
||||||
break;
|
|
||||||
case PronounChoice.jokingly:
|
|
||||||
field.jokingly!.push(pronoun);
|
|
||||||
break;
|
|
||||||
case PronounChoice.friendsOnly:
|
|
||||||
field.friends_only!.push(pronoun);
|
|
||||||
break;
|
|
||||||
case PronounChoice.avoid:
|
|
||||||
field.avoid!.push(pronoun);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return field;
|
return field;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue