[F] Fix userbox

This commit is contained in:
Azalea
2024-12-17 20:36:01 -05:00
parent 637191836a
commit d854d8ae0b
2 changed files with 129 additions and 169 deletions

View File

@@ -8,7 +8,6 @@
import { USER, USERBOX } from "../libs/sdk"; import { USER, USERBOX } from "../libs/sdk";
import { t, ts } from "../libs/i18n"; import { t, ts } from "../libs/i18n";
import { DATA_HOST, HAS_USERBOX_ASSETS } from "../libs/config"; import { DATA_HOST, HAS_USERBOX_ASSETS } from "../libs/config";
import { FADE_IN, FADE_OUT } from "../libs/config";
import { fade, slide } from "svelte/transition"; import { fade, slide } from "svelte/transition";
import StatusOverlays from "./StatusOverlays.svelte"; import StatusOverlays from "./StatusOverlays.svelte";
import Icon from "@iconify/svelte"; import Icon from "@iconify/svelte";
@@ -19,9 +18,6 @@
let submitting = ""; let submitting = "";
let changed: string[] = []; let changed: string[] = [];
let tab = 0;
const tabs = ["chusan", "ongeki", "maimai"];
// Things that can be changed in the userbox // Things that can be changed in the userbox
const userBoxFields = [ const userBoxFields = [
{ {
@@ -149,9 +145,9 @@
const currentValues = await USERBOX.getProfile().catch((e) => { const currentValues = await USERBOX.getProfile().catch((e) => {
loading = false; loading = false;
error = t("userbox.error.noprofile") error = t("userbox.error.noprofile")
}); })
if(!currentValues) return; if (!currentValues) return
values = { values = {
nameplate: currentValues.nameplateId, nameplate: currentValues.nameplateId,
@@ -174,7 +170,7 @@
return return
}); });
if(!itemLabels) return; if (!itemLabels) return;
await Promise.all( await Promise.all(
userBoxItems.map(async (kind) => { userBoxItems.map(async (kind) => {
@@ -300,176 +296,138 @@
</script> </script>
{#if !loading && !error} {#if !loading && !error}
<div class="outer-container"> <div class="fields">
<nav> {#each userBoxFields as { key, label, kind }, i (key)}
{#each tabs as tabName, i} <div class="field">
<div <label for={key}>{label}</label>
transition:slide={{ axis: "x" }} <div>
class:active={tab === i} <select bind:value={values[key]} id={key} on:change={() => changed = [...changed, key]}>
on:click={() => { {#each availableOptions[key] as option}
tab = i; <option value={option.id}>{option.label || `${key} ${option.id.toString()}`}</option>
{/each}
</select>
{#if changed.includes(key)}
<button
transition:slide={{ axis: "x" }}
on:click={() => {
const newValue = values[key];
// Set url params if (newValue === undefined) return;
window.history.pushState({}, "", `/settings?tab=${tab}`);
}}
on:keydown={(e) => e.key === "Enter" && (tab = i)}
role="button"
tabindex="0"
>
{ts(`userbox.tabs.${tabName}`)}
</div>
{/each}
</nav>
{#if tab === 0}
<div class="container" out:fade={FADE_OUT} in:fade={FADE_IN}>
<div class="fields">
{#each userBoxFields as { key, label, kind }, i (key)}
<div class="field">
<label for={key}>{label}</label>
<div>
<select
bind:value={values[key]}
id={key}
on:change={() => {
changed = [...changed, key];
}}
>
{#each availableOptions[key] as option (option)}
<option value={option.id}
>{option.label ||
`${key} ${option.id.toString()}`}</option
>
{/each}
</select>
{#if changed.includes(key)}
<button
transition:slide={{ axis: "x" }}
on:click={() => {
const newValue = values[key];
if (newValue === undefined) return; submit(generateBodyFromKind(key, newValue));
}}
submit(generateBodyFromKind(key, newValue)); >
}} {#if submitting === key}
> <Icon icon="line-md:loading-twotone-loop" />
{#if submitting === key} {:else}
<Icon icon="line-md:loading-twotone-loop" /> {t("settings.profile.save")}
{:else}
{t("settings.profile.save")}
{/if}
</button>
{/if}
</div>
</div>
{/each}
</div>
{#if HAS_USERBOX_ASSETS}
<div class="preview">
<h2>{t("userbox.preview.ui")}</h2>
<!-- Frame -->
{#if values.frame}
<img
src={`${DATA_HOST}/d/chu3/frame/${values.frame}.png`}
alt="Preview"
/>
{/if}
<div class="secondrow">
<!-- Map Icon -->
{#if values.mapicon}
<div class="mapicon">
<img
src={`${DATA_HOST}/d/chu3/mapicon/${values.mapicon}.png`}
alt="Preview"
/>
</div>
{/if} {/if}
</button>
{/if}
</div>
</div>
{/each}
</div>
{#if HAS_USERBOX_ASSETS}
<div class="preview">
<h2>{t("userbox.preview.ui")}</h2>
<!-- Frame -->
{#if values.frame}
<img
src={`${DATA_HOST}/d/chu3/frame/${values.frame}.png`}
alt="Preview"
/>
{/if}
<!-- System voice --> <div class="secondrow">
{#if values.voice} <!-- Map Icon -->
<div> {#if values.mapicon}
<img <div class="mapicon">
src={`${DATA_HOST}/d/chu3/systemVoice/${values.voice}.png`} <img
alt="Preview" src={`${DATA_HOST}/d/chu3/mapicon/${values.mapicon}.png`}
/> alt="Preview"
</div> />
{/if} </div>
</div> {/if}
<h2>{t("userbox.preview.nameplate")}</h2> <!-- System voice -->
<!-- Nameplate --> {#if values.voice}
{#if values.nameplate} <div>
<div class="nameplate"> <img
<img src={`${DATA_HOST}/d/chu3/systemVoice/${values.voice}.png`}
src={`${DATA_HOST}/d/chu3/nameplate/${values.nameplate}.png`} alt="Preview"
alt="Preview" />
/>
<p class="trophy">
{availableOptions.trophy.find((x) => x.id === values.trophy)
?.label}
</p>
<div class="username">
<p>
{user.displayName}
</p>
</div>
</div>
{/if}
<h2>{t("userbox.preview.avatar")}</h2>
<div class="avatar">
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.wear}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.head}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.face}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.skin}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.item}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.front}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.back}.png`}
alt="Preview"
/>
</div>
</div>
</div> </div>
{/if} {/if}
</div> </div>
{:else}
<div> <h2>{t("userbox.preview.nameplate")}</h2>
<p>WIP</p> <!-- Nameplate -->
{#if values.nameplate}
<div class="nameplate">
<img
src={`${DATA_HOST}/d/chu3/nameplate/${values.nameplate}.png`}
alt="Preview"
/>
<p class="trophy">
{availableOptions.trophy.find((x) => x.id === values.trophy)
?.label}
</p>
<div class="username">
<p>
{user.displayName}
</p>
</div>
</div>
{/if}
<h2>{t("userbox.preview.avatar")}</h2>
<div class="avatar">
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.wear}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.head}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.face}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.skin}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.item}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.front}.png`}
alt="Preview"
/>
</div>
<div>
<img
src={`${DATA_HOST}/d/chu3/avatarAccessory/${values.back}.png`}
alt="Preview"
/>
</div>
</div> </div>
{/if} </div>
</div> {/if}
{/if} {/if}
<StatusOverlays {error} {loading} /> <StatusOverlays {error} {loading} />

View File

@@ -266,7 +266,9 @@ export const USERBOX = {
get('/api/v2/game/chu3/user-box', {}), get('/api/v2/game/chu3/user-box', {}),
getUnlockedItems: (itemId: UserBoxItemKind): Promise<{ itemKind: number, itemId: number, stock: number, isValid: boolean }[]> => getUnlockedItems: (itemId: UserBoxItemKind): Promise<{ itemKind: number, itemId: number, stock: number, isValid: boolean }[]> =>
get(`/api/v2/game/chu3/user-box-item-by-kind`,{ itemId }), get(`/api/v2/game/chu3/user-box-item-by-kind`,{ itemId }),
getItemLabels: () => get(`/api/v2/game/chu3/user-box-all-items`, {}), getItemLabels: () => get(`/api/v2/game/chu3/user-box-all-items`, {}).then(it =>
Object.fromEntries(Object.entries(it).map(([key, value]) =>
[key, Object.fromEntries((value as any[]).map(it => [it.id, it.name]))]))),
setUserBox: (d: { field: string, value: number | string }) => setUserBox: (d: { field: string, value: number | string }) =>
post(`/api/v2/game/chu3/user-detail-set`, d), post(`/api/v2/game/chu3/user-detail-set`, d),
} }