224 lines
7.4 KiB
TypeScript
224 lines
7.4 KiB
TypeScript
import { useNavigate, useParams } from "@solidjs/router";
|
|
import { Component, Show, createEffect, createSignal } from "solid-js";
|
|
|
|
import styles from './GroupPage.module.css'
|
|
import { Group, Map, Profile, Strat, User, api } from "../api";
|
|
import { showDialog, showInputDialog, showMessageDialog } from "../state";
|
|
import { _arrayBufferToBase64, errorToString, normalize } from "../util";
|
|
import { BsCheck2, BsPencil, BsTrash } from "solid-icons/bs";
|
|
import { Collapse } from "solid-collapse";
|
|
import MemberItem from "../components/MemberItem";
|
|
import MapItem from "../components/MapItem";
|
|
import StratItem from "../components/StratItem";
|
|
import StratTypeItem from "../components/StratTypeItem";
|
|
import ProfileItem from "../components/ProfileItem";
|
|
import { UploadFile, createFileUploader } from "@solid-primitives/upload";
|
|
|
|
const GroupPage: Component = () => {
|
|
const params = useParams();
|
|
const navigate = useNavigate();
|
|
|
|
const [loading, setLoading] = createSignal(true);
|
|
const [group, setGroup] = createSignal({} as Group);
|
|
const [editing, setEditing] = createSignal(false);
|
|
const [name, setName] = createSignal('');
|
|
|
|
const [membersIsExpanded, setMembersIsExpanded] = createSignal(false);
|
|
const [mapsIsExpanded, setMapsIsExpanded] = createSignal(false);
|
|
const [stratsIsExpanded, setStratsIsExpanded] = createSignal(false);
|
|
const [profilesIsExpanded, setProfilesIsExpanded] = createSignal(false);
|
|
const [stratTypesIsExpanded, setStratTypesIsExpanded] = createSignal(false);
|
|
|
|
createEffect(async () => {
|
|
try {
|
|
setGroup(await api().getGroup(params.id));
|
|
setName(group().name);
|
|
setLoading(false);
|
|
} catch (e) {
|
|
showMessageDialog('Failed to load group', errorToString(e));
|
|
}
|
|
}, []);
|
|
|
|
const updateGroup = async (newValue: Group) => {
|
|
try {
|
|
await api().updateGroup(group().id, newValue);
|
|
setGroup(newValue);
|
|
} catch (e) {
|
|
showMessageDialog('Failed to update group', errorToString(e));
|
|
}
|
|
};
|
|
|
|
const deleteGroup = async () => {
|
|
showDialog({
|
|
title: 'Delete group',
|
|
text: 'Do you want to delete this group?',
|
|
buttons: [
|
|
{
|
|
name: 'Delete',
|
|
type: 'danger',
|
|
action: async () => {
|
|
try {
|
|
await api().removeGroup(group().id);
|
|
navigate('/groups');
|
|
} catch (e) {
|
|
showMessageDialog('Failed to delete group', errorToString(e));
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'Cancel',
|
|
action: () => { }
|
|
}
|
|
]
|
|
});
|
|
};
|
|
|
|
const addMember = async () => {
|
|
showInputDialog('Add member to Group', 'enter the member id you want to add', 'member ID', async (memberId) => {
|
|
try {
|
|
const newGroup = await api().addMember(group().id, memberId);
|
|
setGroup(newGroup);
|
|
} catch (e) {
|
|
showMessageDialog('Failed to add member', errorToString(e));
|
|
}
|
|
})
|
|
};
|
|
|
|
const addStratType = async () => {
|
|
showInputDialog('Add strat type to Group', 'enter the name you want to add', 'strat type', async (stratType) => {
|
|
try {
|
|
const newGroup = await api().addStratType(group().id, stratType);
|
|
setGroup(newGroup);
|
|
} catch (e) {
|
|
showMessageDialog('Failed to add strat type', errorToString(e));
|
|
}
|
|
})
|
|
};
|
|
|
|
const addProfile = async () => {
|
|
const [profileName, setProfileName] = createSignal('');
|
|
const { files, selectFiles } = createFileUploader({
|
|
multiple: false,
|
|
accept: "image/*",
|
|
});
|
|
|
|
let fileReader = new FileReader();
|
|
|
|
fileReader.onload = async event => {
|
|
try {
|
|
const newGroup = await api().addProfileToGroup(group().id, { name: profileName(), image: _arrayBufferToBase64(event.target!.result as ArrayBuffer) });
|
|
setGroup(newGroup);
|
|
} catch (e) {
|
|
showMessageDialog('Failed to add profile', errorToString(e));
|
|
}
|
|
}
|
|
|
|
showDialog({
|
|
title: 'Add profile to Group',
|
|
text: 'create a new profile',
|
|
inputFields: [{
|
|
onInput: setProfileName,
|
|
placeholder: 'name'
|
|
}],
|
|
onDismiss: async () => {
|
|
fileReader.readAsArrayBuffer(files()[0].file);
|
|
},
|
|
buttons: [{
|
|
name: 'add image', action: () => selectFiles(([{ source, name, size, file }]) => {
|
|
console.log({ source, name, size, file });
|
|
}),
|
|
closeOnClick: false
|
|
},
|
|
'confirm'
|
|
],
|
|
})
|
|
};
|
|
|
|
const toggleEdit = async () => {
|
|
if (!editing()) {
|
|
setEditing(true);
|
|
} else {
|
|
console.log(name());
|
|
updateGroup({ ...group(), name: name() });
|
|
setEditing(false);
|
|
}
|
|
};
|
|
|
|
const onDeleteMember = async (member: User) => {
|
|
setGroup({ ...group(), members: [...group().members.filter(m => m.username !== member.username)] });
|
|
};
|
|
|
|
const onDeleteMap = async (map: Map) => {
|
|
setGroup({ ...group(), maps: [...group().maps.filter(m => m.id !== map.id)] });
|
|
};
|
|
|
|
const onDeleteStrat = async (strat: Strat) => {
|
|
setGroup({ ...group(), strats: [...group().strats.filter(s => s.id !== strat.id)] });
|
|
};
|
|
|
|
const onDeleteStratType = async (stratType: string) => {
|
|
setGroup({ ...group(), stratTypes: [...group().stratTypes.filter(s => s !== stratType)] });
|
|
};
|
|
|
|
const onDeleteProfile = async (profile: Profile) => {
|
|
setGroup({ ...group(), profiles: [...group().profiles.filter(p => p.id !== profile.id)] });
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Show when={!loading()} fallback={<div>Loading...</div>}>
|
|
<div class={styles.groupName}>
|
|
<span contentEditable={editing()} innerText={group().name} onInput={e => setName(normalize(e.currentTarget.innerText, 50, true))} />
|
|
{editing() && <span class={styles.editCount}>{name().length}/50</span>}
|
|
</div>
|
|
<div class={styles.groupButtons}>
|
|
<button class={styles.deleteButton} onClick={deleteGroup}>Delete group</button>
|
|
<button class={styles.editButton} onClick={toggleEdit}>{editing() ? <BsCheck2 /> : <BsPencil />}</button>
|
|
</div>
|
|
<hr />
|
|
<div>
|
|
<button onClick={() => setMembersIsExpanded(!membersIsExpanded())}>Members</button>
|
|
<button class={styles.addMemberButton} onClick={addMember}>+</button>
|
|
<Collapse value={membersIsExpanded()} class={styles.members}>
|
|
<div class={styles.groupMembers}>
|
|
{group().members?.map(m => <MemberItem group={group()} member={m} onDelete={onDeleteMember} />)}
|
|
</div>
|
|
</Collapse>
|
|
<br />
|
|
<button onClick={() => setStratsIsExpanded(!stratsIsExpanded())}>strats</button>
|
|
<Collapse value={stratsIsExpanded()} class={styles.strats}>
|
|
<div class={styles.strats}>
|
|
{group().strats?.map(s => <StratItem group={group()} strat={s} onDelete={onDeleteStrat} />)}
|
|
</div>
|
|
</Collapse>
|
|
<br />
|
|
<button onClick={() => setMapsIsExpanded(!mapsIsExpanded())}>maps</button>
|
|
<Collapse value={mapsIsExpanded()} class={styles.maps}>
|
|
<div class={styles.maps}>
|
|
{group().maps?.map(m => <MapItem group={group()} map={m} onDelete={onDeleteMap} />)}
|
|
</div>
|
|
</Collapse>
|
|
<br />
|
|
<button onClick={() => setStratTypesIsExpanded(!stratTypesIsExpanded())}>strat types</button>
|
|
<button class={styles.addMemberButton} onClick={addStratType}>+</button>
|
|
<Collapse value={stratTypesIsExpanded()} class={styles.stratTypes}>
|
|
<div class={styles.stratTypes}>
|
|
{group().stratTypes?.map(s => <StratTypeItem group={group()} stratType={s} onDelete={onDeleteStratType} />)}
|
|
</div>
|
|
</Collapse>
|
|
<br />
|
|
<button onClick={() => setProfilesIsExpanded(!profilesIsExpanded())}>profiles</button>
|
|
<button class={styles.addMemberButton} onClick={addProfile}>+</button>
|
|
<Collapse value={profilesIsExpanded()} class={styles.profiles}>
|
|
<div class={styles.profiles}>
|
|
{group().profiles?.map(p => <ProfileItem group={group()} profile={p} onDelete={onDeleteProfile} />)}
|
|
</div>
|
|
</Collapse>
|
|
</div>
|
|
</Show>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default GroupPage;
|