most add/delete api cals in use
This commit is contained in:
parent
4aae0c1724
commit
f06fbd69a9
@ -5,7 +5,8 @@ import { A, HashRouter, Route, RouteSectionProps, useNavigate } from '@solidjs/r
|
||||
import Login from './pages/Login';
|
||||
import Groups from './pages/Groups';
|
||||
import Account from './pages/Account';
|
||||
import GroupPage from './pages/GroupPage'
|
||||
import GroupPage from './pages/GroupPage';
|
||||
import StratPage from './pages/StratPage';
|
||||
|
||||
import { BsArrowBarRight, BsBookmarkHeartFill, BsPeopleFill } from 'solid-icons/bs';
|
||||
import { API, api, setAPI, setAuthConfig } from './api';
|
||||
@ -88,6 +89,7 @@ const App: Component = () => {
|
||||
<HashRouter root={AppLayout}>
|
||||
<Route path='groups' component={Groups} />
|
||||
<Route path='group/:id' component={GroupPage} />
|
||||
<Route path='group/:groupId/strat/:stratId' component={StratPage} />
|
||||
{localState.accountInfo != null ?
|
||||
<>
|
||||
<Route path='account' component={Account} />
|
||||
|
@ -81,13 +81,11 @@ export interface StratRequest {
|
||||
title: string,
|
||||
description: string,
|
||||
stratType: string,
|
||||
attempts: number,
|
||||
success: number,
|
||||
}
|
||||
|
||||
export interface MapRequest {
|
||||
name: string,
|
||||
image: File,
|
||||
image: string,
|
||||
}
|
||||
|
||||
export interface ProfileRequest {
|
||||
@ -102,12 +100,12 @@ export interface PlayerTypeRequest {
|
||||
|
||||
export interface StratStateRequest {
|
||||
description: string,
|
||||
image: File,
|
||||
image: string,
|
||||
}
|
||||
|
||||
export interface LineupRequest {
|
||||
description: string,
|
||||
image: File,
|
||||
image: string,
|
||||
}
|
||||
|
||||
export class API {
|
||||
|
@ -1,58 +1,54 @@
|
||||
import { Component, For, Setter, Show } from 'solid-js';
|
||||
import { Component, createSignal, For, JSX } from 'solid-js';
|
||||
|
||||
import styles from './Dialog.module.css';
|
||||
import { UploadFile, FileUploader } from '@solid-primitives/upload';
|
||||
import DialogButtonComponent from './DialogButtonComponent';
|
||||
|
||||
export interface DialogButton {
|
||||
name: string,
|
||||
action?: () => void,
|
||||
type?: 'default' | 'danger' | 'success',
|
||||
closeOnClick?: boolean
|
||||
action?: () => void | boolean | Promise<void> | Promise<boolean>,
|
||||
type?: 'default' | 'danger' | 'success'
|
||||
}
|
||||
|
||||
export interface DialogInputField {
|
||||
placeholder: string,
|
||||
onInput: (text: string) => void,
|
||||
}
|
||||
|
||||
export interface ImageInputField {
|
||||
name: string,
|
||||
onInput: () => Setter<UploadFile[]>,
|
||||
placeholder?: string,
|
||||
onInput: (text: string) => void,
|
||||
}
|
||||
|
||||
export interface DialogProps {
|
||||
title: string,
|
||||
text: string,
|
||||
text?: string,
|
||||
buttons?: (string | DialogButton)[],
|
||||
onDismiss?: () => void,
|
||||
inputFields?: DialogInputField[],
|
||||
}
|
||||
|
||||
function createButton(button: (string | DialogButton), dismiss?: () => void) { //TODO configurable if dismiss on click
|
||||
if (typeof button == 'string') {
|
||||
return <button onclick={dismiss} class={styles.defaultButton}>{button}</button>;
|
||||
} else {
|
||||
return <button onclick={() => { button.action?.(); button.closeOnClick ? dismiss?.() : () => { }; }} class={styles[button.type + 'Button']}>{button.name}</button>;
|
||||
}
|
||||
content?: JSX.Element,
|
||||
}
|
||||
|
||||
function createInputField(field: DialogInputField) {
|
||||
return <input placeholder={field.placeholder} onInput={e => field.onInput(e.currentTarget.value)}></input>
|
||||
return <div class={styles.dialogInput}>
|
||||
<span>{field.name}</span>
|
||||
<input placeholder={field.placeholder ?? field.name} onInput={e => field.onInput(e.currentTarget.value)}></input>
|
||||
</div>;
|
||||
}
|
||||
|
||||
const Dialog: Component<DialogProps> = props => {
|
||||
const buttons: () => (string | DialogButton)[] = () => props.buttons == null ? [{ name: 'Okay', action: props.onDismiss }] : props.buttons;
|
||||
const buttons: () => (string | DialogButton)[] = () => props.buttons == null ? ["Okay"] : props.buttons;
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
return (
|
||||
<div class={styles.dialogContainer}>
|
||||
<div class={styles.dialog}>
|
||||
<div class={styles.dialogTitle}>{props.title}</div>
|
||||
<div class={styles.dialogText}>{props.text}</div>
|
||||
<div class={styles.dialogInputFields}>
|
||||
{props.inputFields && props.inputFields.length > 0 && <div class={styles.dialogInputFields}>
|
||||
<For each={props.inputFields}>{f => createInputField(f)}</For>
|
||||
</div>
|
||||
</div>}
|
||||
{props.content}
|
||||
<div class={styles.dialogButtons}>
|
||||
<For each={buttons()}>{b => createButton(b, props.onDismiss)}</For>
|
||||
<For each={buttons()}>{b => //createButton(b, props.onDismiss);
|
||||
<DialogButtonComponent button={b} dismiss={props.onDismiss} loading={loading()} setLoading={setLoading} />
|
||||
}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
27
src/components/DialogButtonComponent.tsx
Normal file
27
src/components/DialogButtonComponent.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { Component } from "solid-js";
|
||||
import { DialogButton } from "./Dialog";
|
||||
import styles from './Dialog.module.css';
|
||||
|
||||
export interface DialogButtonProps {
|
||||
dismiss?: () => void
|
||||
button: string | DialogButton
|
||||
loading: boolean
|
||||
setLoading: (b: boolean) => void
|
||||
}
|
||||
|
||||
const DialogButtonComponent: Component<DialogButtonProps> = (props) => {
|
||||
if (typeof props.button == 'string') {
|
||||
return <button onclick={props.dismiss} class={styles.defaultButton}>{props.button}</button>;
|
||||
} else {
|
||||
const clickHandler = () => {
|
||||
props.setLoading(true);
|
||||
Promise.resolve((props.button as DialogButton).action?.()).then(v => {
|
||||
if (v === undefined || v === true) props.dismiss?.();
|
||||
props.setLoading(false);
|
||||
});
|
||||
};
|
||||
return <button disabled={props.loading} onclick={clickHandler} class={styles[props.button.type + 'Button']}>{props.button.name}</button>;
|
||||
}
|
||||
}
|
||||
|
||||
export default DialogButtonComponent;
|
@ -21,7 +21,6 @@ const ProfileItem: Component<ProfileItemProps> = (props) => {
|
||||
{
|
||||
name: 'Remove',
|
||||
type: 'danger',
|
||||
closeOnClick: true,
|
||||
action: async () => {
|
||||
try {
|
||||
await api().removeProfileFromGroup(props.group.id, props.profile.id);
|
||||
@ -31,11 +30,7 @@ const ProfileItem: Component<ProfileItemProps> = (props) => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Cancel',
|
||||
closeOnClick: true,
|
||||
action: () => { }
|
||||
}
|
||||
'Cancel'
|
||||
]
|
||||
});
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import { Group, Strat, api } from "../api";
|
||||
import { showDialog, showMessageDialog } from "../state";
|
||||
import { errorToString } from "../util";
|
||||
import { BsTrash } from 'solid-icons/bs';
|
||||
import { useNavigate } from '@solidjs/router';
|
||||
|
||||
export interface StratItemProps {
|
||||
group: Group,
|
||||
@ -12,6 +13,7 @@ export interface StratItemProps {
|
||||
}
|
||||
|
||||
const StratItem: Component<StratItemProps> = (props) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const deleteMember = async () => {
|
||||
showDialog({
|
||||
@ -41,10 +43,10 @@ const StratItem: Component<StratItemProps> = (props) => {
|
||||
return (
|
||||
<div class={styles.member}>
|
||||
<div class={styles.memberDetails}>
|
||||
<div class={styles.memberName}>
|
||||
<div class={styles.memberName} onclick={() => navigate('/group/' + props.group.id + '/strat/' + props.strat.id)}>
|
||||
<span innerText={props.strat.title} />
|
||||
<span innerText={props.strat.description} />
|
||||
<span innerText={props.strat.stratType} />
|
||||
<span innerText={props.strat.map.name} />
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={deleteMember}><BsTrash /></button>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useNavigate, useParams } from "@solidjs/router";
|
||||
import { Component, Show, createEffect, createSignal } from "solid-js";
|
||||
import { Component, Show, createEffect, createSignal, onMount } 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 { _arrayBufferToBase64, addMap, addMember, addProfile, addStratType, errorToString, normalize } from "../util";
|
||||
import { BsCheck2, BsPencil, BsTrash } from "solid-icons/bs";
|
||||
import { Collapse } from "solid-collapse";
|
||||
import MemberItem from "../components/MemberItem";
|
||||
@ -29,7 +29,7 @@ const GroupPage: Component = () => {
|
||||
const [profilesIsExpanded, setProfilesIsExpanded] = createSignal(false);
|
||||
const [stratTypesIsExpanded, setStratTypesIsExpanded] = createSignal(false);
|
||||
|
||||
createEffect(async () => {
|
||||
onMount(async () => {
|
||||
try {
|
||||
setGroup(await api().getGroup(params.id));
|
||||
setName(group().name);
|
||||
@ -37,7 +37,7 @@ const GroupPage: Component = () => {
|
||||
} catch (e) {
|
||||
showMessageDialog('Failed to load group', errorToString(e));
|
||||
}
|
||||
}, []);
|
||||
});
|
||||
|
||||
const updateGroup = async (newValue: Group) => {
|
||||
try {
|
||||
@ -73,66 +73,34 @@ const GroupPage: Component = () => {
|
||||
});
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
const createStrat = async () => {
|
||||
const [title, setTitle] = createSignal('');
|
||||
const [description, setDescription] = createSignal('');
|
||||
const [stratType, setStratType] = createSignal('');
|
||||
|
||||
showDialog({
|
||||
title: 'Add profile to Group',
|
||||
text: 'create a new profile',
|
||||
title: 'Add a strat to Group',
|
||||
text: 'create a new strat',
|
||||
inputFields: [{
|
||||
onInput: setProfileName,
|
||||
placeholder: 'name'
|
||||
onInput: setTitle,
|
||||
placeholder: 'title',
|
||||
name: 'title'
|
||||
}, {
|
||||
onInput: setDescription,
|
||||
placeholder: 'description',
|
||||
name: 'description'
|
||||
}],
|
||||
onDismiss: async () => {
|
||||
fileReader.readAsArrayBuffer(files()[0].file);
|
||||
const strat = await api().addStrat(group().id, { title: title(), description: description(), stratType: stratType() });
|
||||
navigate('/group/' + group().id + '/strat/' + strat.id);
|
||||
},
|
||||
buttons: [{
|
||||
name: 'add image', action: () => selectFiles(([{ source, name, size, file }]) => {
|
||||
console.log({ source, name, size, file });
|
||||
}),
|
||||
closeOnClick: false
|
||||
},
|
||||
'confirm'
|
||||
],
|
||||
})
|
||||
};
|
||||
content: <select name="stratType" id="stratType">
|
||||
{group().stratTypes.map(p => <option value={p} onclick={() => setStratType(p)}>{p}</option>)}
|
||||
</select>,
|
||||
buttons: ['confirm'],
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const toggleEdit = async () => {
|
||||
if (!editing()) {
|
||||
@ -178,7 +146,7 @@ const GroupPage: Component = () => {
|
||||
<hr />
|
||||
<div>
|
||||
<button onClick={() => setMembersIsExpanded(!membersIsExpanded())}>Members</button>
|
||||
<button class={styles.addMemberButton} onClick={addMember}>+</button>
|
||||
<button class={styles.addMemberButton} onClick={async () => addMember(group(), (g) => setGroup(g))}>+</button>
|
||||
<Collapse value={membersIsExpanded()} class={styles.members}>
|
||||
<div class={styles.groupMembers}>
|
||||
{group().members?.map(m => <MemberItem group={group()} member={m} onDelete={onDeleteMember} />)}
|
||||
@ -186,6 +154,7 @@ const GroupPage: Component = () => {
|
||||
</Collapse>
|
||||
<br />
|
||||
<button onClick={() => setStratsIsExpanded(!stratsIsExpanded())}>strats</button>
|
||||
<button class={styles.addStratButton} onClick={() => createStrat()}>+</button>
|
||||
<Collapse value={stratsIsExpanded()} class={styles.strats}>
|
||||
<div class={styles.strats}>
|
||||
{group().strats?.map(s => <StratItem group={group()} strat={s} onDelete={onDeleteStrat} />)}
|
||||
@ -193,6 +162,7 @@ const GroupPage: Component = () => {
|
||||
</Collapse>
|
||||
<br />
|
||||
<button onClick={() => setMapsIsExpanded(!mapsIsExpanded())}>maps</button>
|
||||
<button class={styles.addMapButton} onClick={async () => addMap(group(), (g) => setGroup(g))}>+</button>
|
||||
<Collapse value={mapsIsExpanded()} class={styles.maps}>
|
||||
<div class={styles.maps}>
|
||||
{group().maps?.map(m => <MapItem group={group()} map={m} onDelete={onDeleteMap} />)}
|
||||
@ -200,7 +170,7 @@ const GroupPage: Component = () => {
|
||||
</Collapse>
|
||||
<br />
|
||||
<button onClick={() => setStratTypesIsExpanded(!stratTypesIsExpanded())}>strat types</button>
|
||||
<button class={styles.addMemberButton} onClick={addStratType}>+</button>
|
||||
<button class={styles.addMemberButton} onClick={async () => addStratType(group(), (g) => setGroup(g))}>+</button>
|
||||
<Collapse value={stratTypesIsExpanded()} class={styles.stratTypes}>
|
||||
<div class={styles.stratTypes}>
|
||||
{group().stratTypes?.map(s => <StratTypeItem group={group()} stratType={s} onDelete={onDeleteStratType} />)}
|
||||
@ -208,7 +178,7 @@ const GroupPage: Component = () => {
|
||||
</Collapse>
|
||||
<br />
|
||||
<button onClick={() => setProfilesIsExpanded(!profilesIsExpanded())}>profiles</button>
|
||||
<button class={styles.addMemberButton} onClick={addProfile}>+</button>
|
||||
<button class={styles.addMemberButton} onClick={async () => addProfile(group(), (g) => setGroup(g))}>+</button>
|
||||
<Collapse value={profilesIsExpanded()} class={styles.profiles}>
|
||||
<div class={styles.profiles}>
|
||||
{group().profiles?.map(p => <ProfileItem group={group()} profile={p} onDelete={onDeleteProfile} />)}
|
||||
|
7
src/pages/StratPage.tsx
Normal file
7
src/pages/StratPage.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import { Component } from "solid-js";
|
||||
|
||||
const StratPage: Component = () => {
|
||||
return <>strat page</>
|
||||
}
|
||||
|
||||
export default StratPage
|
14
src/state.ts
14
src/state.ts
@ -1,7 +1,7 @@
|
||||
import { createEffect, createSignal } from 'solid-js';
|
||||
import { SetStoreFunction, Store, createStore } from 'solid-js/store';
|
||||
import { AuthenticationResponse } from './api';
|
||||
import { DialogInputField, DialogProps, ImageInputField } from './components/Dialog';
|
||||
import { DialogInputField, DialogProps } from './components/Dialog';
|
||||
|
||||
// Source: https://www.solidjs.com/examples/todos
|
||||
function createLocalStore<T extends object>(
|
||||
@ -30,7 +30,9 @@ export const showDialog = (dialog: DialogProps) => {
|
||||
onDismiss: () => {
|
||||
setDialogs(ds => {
|
||||
const newDs = [...ds];
|
||||
newDs.splice(ds.indexOf(newDialog), 1);
|
||||
let idx = ds.indexOf(newDialog);
|
||||
if (idx == -1) return newDs;
|
||||
newDs.splice(idx, 1);
|
||||
return newDs;
|
||||
});
|
||||
dialog.onDismiss?.();
|
||||
@ -40,14 +42,14 @@ export const showDialog = (dialog: DialogProps) => {
|
||||
setDialogs([...dialogs(), newDialog]);
|
||||
};
|
||||
|
||||
export const showInputDialog = (title: string, message: string, placeholder: string, callback: (text: string) => void) => {
|
||||
export const showInputDialog = (title: string, message: string, name: string, callback: (text: string) => void) => {
|
||||
const [text, setText] = createSignal('');
|
||||
|
||||
showDialog({
|
||||
title,
|
||||
text: message,
|
||||
inputFields: [{ placeholder, onInput: setText }],
|
||||
buttons: [{ name: 'Okay', action: () => callback(text()), closeOnClick: true }]
|
||||
inputFields: [{ name, onInput: setText }],
|
||||
buttons: [{ name: 'Okay', action: () => callback(text()) }, "cancel"]
|
||||
});
|
||||
}
|
||||
|
||||
@ -56,7 +58,7 @@ export const showInputsDialog = async (title: string, message: string, inputFiel
|
||||
title,
|
||||
text: message,
|
||||
inputFields: inputFields,
|
||||
buttons: [{ name: 'Okay', action: () => callback(), closeOnClick: true }]
|
||||
buttons: [{ name: 'Okay', action: () => callback() }]
|
||||
});
|
||||
}
|
||||
|
||||
|
69
src/util.ts
69
src/util.ts
@ -1,69 +0,0 @@
|
||||
export function errorToString(e: any): string { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (typeof e == 'string') {
|
||||
return e;
|
||||
} else if (e.toString) {
|
||||
return e.toString() as string;
|
||||
} else {
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
|
||||
export function normalize(text: string, maxLength: number, oneLine: boolean) {
|
||||
if (oneLine) text = text.replaceAll('\n', '');
|
||||
text = text.substring(0, maxLength);
|
||||
return text;
|
||||
}
|
||||
|
||||
export function normalizeQuantity(text: string) {
|
||||
let quantity = parseInt(text);
|
||||
|
||||
if (isNaN(quantity) || quantity < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
};
|
||||
|
||||
export function normalizeRating(text: string) {
|
||||
let rating = parseInt(text);
|
||||
|
||||
if (isNaN(rating)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return clamp(rating, 0, 5);
|
||||
}
|
||||
|
||||
export function _arrayBufferToBase64(buffer: ArrayBuffer) {
|
||||
var binary = '';
|
||||
var bytes = new Uint8Array(buffer);
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
export const b64toBlob = (b64Data: string, contentType = '', sliceSize = 512) => {
|
||||
const byteCharacters = atob(b64Data);
|
||||
const byteArrays = [];
|
||||
|
||||
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||
|
||||
const byteNumbers = new Array(slice.length);
|
||||
for (let i = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = slice.charCodeAt(i);
|
||||
}
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
byteArrays.push(byteArray);
|
||||
}
|
||||
|
||||
const blob = new Blob(byteArrays, { type: contentType });
|
||||
return blob;
|
||||
}
|
164
src/util.tsx
Normal file
164
src/util.tsx
Normal file
@ -0,0 +1,164 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { api, Group } from "./api";
|
||||
import { showDialog, showInputDialog, showMessageDialog } from "./state";
|
||||
import { createFileUploader } from "@solid-primitives/upload";
|
||||
|
||||
export function errorToString(e: any): string { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if (typeof e == 'string') {
|
||||
return e;
|
||||
} else if (e.toString) {
|
||||
return e.toString() as string;
|
||||
} else {
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
|
||||
export function normalize(text: string, maxLength: number, oneLine: boolean) {
|
||||
if (oneLine) text = text.replaceAll('\n', '');
|
||||
text = text.substring(0, maxLength);
|
||||
return text;
|
||||
}
|
||||
|
||||
export function normalizeQuantity(text: string) {
|
||||
let quantity = parseInt(text);
|
||||
|
||||
if (isNaN(quantity) || quantity < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
};
|
||||
|
||||
export function normalizeRating(text: string) {
|
||||
let rating = parseInt(text);
|
||||
|
||||
if (isNaN(rating)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return clamp(rating, 0, 5);
|
||||
}
|
||||
|
||||
export function _arrayBufferToBase64(buffer: ArrayBuffer) {
|
||||
var binary = '';
|
||||
var bytes = new Uint8Array(buffer);
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
export const b64toBlob = (b64Data: string, contentType = '', sliceSize = 512) => {
|
||||
const byteCharacters = atob(b64Data);
|
||||
const byteArrays = [];
|
||||
|
||||
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||
|
||||
const byteNumbers = new Array(slice.length);
|
||||
for (let i = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = slice.charCodeAt(i);
|
||||
}
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
byteArrays.push(byteArray);
|
||||
}
|
||||
|
||||
const blob = new Blob(byteArrays, { type: contentType });
|
||||
return blob;
|
||||
}
|
||||
|
||||
export const addMember = (group: Group, onClose: (newGroup: Group) => void) => {
|
||||
showInputDialog('Add member to Group', 'enter the member id you want to add', 'member ID', async (memberId) => {
|
||||
try {
|
||||
onClose(await api().addMember(group.id, memberId));
|
||||
} catch (e) {
|
||||
showMessageDialog('Failed to add member', errorToString(e));
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
export const addStratType = (group: Group, onClose: (newGroup: Group) => void) => {
|
||||
showInputDialog('Add strat type to Group', 'enter the name you want to add', 'strat type', async (stratType) => {
|
||||
try {
|
||||
onClose(await api().addStratType(group.id, stratType));
|
||||
} catch (e) {
|
||||
showMessageDialog('Failed to add strat type', errorToString(e));
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
export const addProfile = (group: Group, onClose: (newGroup: Group) => void) => {
|
||||
const [profileName, setProfileName] = createSignal('');
|
||||
const { files, selectFiles } = createFileUploader({
|
||||
multiple: false,
|
||||
accept: "image/*",
|
||||
});
|
||||
|
||||
let fileReader = new FileReader();
|
||||
|
||||
fileReader.onload = async event => {
|
||||
try {
|
||||
onClose(await api().addProfileToGroup(group.id, { name: profileName(), image: _arrayBufferToBase64(event.target!.result as ArrayBuffer) }));
|
||||
} 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',
|
||||
name: 'name'
|
||||
}],
|
||||
onDismiss: async () => {
|
||||
fileReader.readAsArrayBuffer(files()[0].file);
|
||||
},
|
||||
content: <button onclick={() => selectFiles(([{ source, name, size, file }]) => {
|
||||
console.log({ source, name, size, file });
|
||||
})}> Add Image </button>,
|
||||
buttons: ['confirm'],
|
||||
});
|
||||
};
|
||||
|
||||
export const addMap = async (group: Group, onClose: (newGroup: Group) => void) => {
|
||||
const [mapName, setMapName] = createSignal('');
|
||||
const { files, selectFiles } = createFileUploader({
|
||||
multiple: false,
|
||||
accept: "image/*",
|
||||
});
|
||||
|
||||
let fileReader = new FileReader();
|
||||
|
||||
fileReader.onload = async event => {
|
||||
try {
|
||||
onClose(await api().addMap(group.id, { name: mapName(), image: _arrayBufferToBase64(event.target!.result as ArrayBuffer) }));
|
||||
} catch (e) {
|
||||
showMessageDialog('Failed to add map', errorToString(e));
|
||||
}
|
||||
}
|
||||
|
||||
showDialog({
|
||||
title: 'Add map to Group',
|
||||
text: 'create a new map',
|
||||
inputFields: [{
|
||||
onInput: setMapName,
|
||||
placeholder: 'name',
|
||||
name: 'name'
|
||||
}],
|
||||
onDismiss: async () => {
|
||||
fileReader.readAsArrayBuffer(files()[0].file);
|
||||
},
|
||||
content: <button onclick={() => selectFiles(([{ source, name, size, file }]) => {
|
||||
console.log({ source, name, size, file });
|
||||
})}> Add Image </button>,
|
||||
buttons: ['confirm'],
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue
Block a user