Add detail to wish counter
parent
8d3fd97d6b
commit
932f03e377
|
@ -6,7 +6,7 @@
|
|||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let className;
|
||||
export let className = '';
|
||||
export let icon = null;
|
||||
export let options;
|
||||
export let placeholder = 'Select...';
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import Select from '../components/Select.svelte';
|
||||
import CharacterSelect from '../components/CharacterSelect.svelte';
|
||||
import WeaponSelect from '../components/WeaponSelect.svelte';
|
||||
import Input from '../components/Input.svelte';
|
||||
import Button from './Button.svelte';
|
||||
import { weaponList } from '../data/weaponList';
|
||||
import { characters } from '../data/characters';
|
||||
|
||||
export let addPullDetail = () => {};
|
||||
export let editPullDetail = () => {};
|
||||
export let deletePullDetail = () => {};
|
||||
export let pity;
|
||||
export let skip;
|
||||
|
||||
export let isEdit = false;
|
||||
export let editType = '';
|
||||
export let editName = '';
|
||||
export let editTime = '';
|
||||
|
||||
let selectOptions = [
|
||||
{ label: 'Character', value: 'character' },
|
||||
{ label: 'Weapon', value: 'weapon' },
|
||||
];
|
||||
let type;
|
||||
let name;
|
||||
let time = dayjs().format('YYYY-MM-DDTHH:mm');
|
||||
|
||||
onMount(() => {
|
||||
if (!isEdit) return;
|
||||
|
||||
type = selectOptions.find((e) => e.value === editType);
|
||||
|
||||
if (editType === 'character') {
|
||||
name = characters[editName];
|
||||
} else {
|
||||
name = weaponList[editName];
|
||||
}
|
||||
|
||||
time = dayjs.unix(editTime).format('YYYY-MM-DDTHH:mm');
|
||||
});
|
||||
|
||||
function add() {
|
||||
const pull = {
|
||||
type: type.value,
|
||||
id: name.id,
|
||||
time: dayjs(time).unix(),
|
||||
pity,
|
||||
};
|
||||
|
||||
addPullDetail(pull);
|
||||
}
|
||||
|
||||
function edit() {
|
||||
const pull = {
|
||||
type: type.value,
|
||||
id: name.id,
|
||||
time: dayjs(time).unix(),
|
||||
pity,
|
||||
};
|
||||
|
||||
editPullDetail(pull);
|
||||
}
|
||||
|
||||
function deleteDetail() {
|
||||
deletePullDetail();
|
||||
}
|
||||
|
||||
$: disabled = !name || !time;
|
||||
</script>
|
||||
|
||||
<div class="text-white">
|
||||
<p class="font-display font-bold mb-4">Add Pull Detail</p>
|
||||
<Select options={selectOptions} bind:selected={type} placeholder="Select Type..." />
|
||||
<div class="h-4" />
|
||||
{#if type && type.value === 'weapon'}
|
||||
<WeaponSelect bind:selected={name} />
|
||||
{:else}
|
||||
<CharacterSelect bind:selected={name} />
|
||||
{/if}
|
||||
<div class="h-4" />
|
||||
<Input type="datetime-local" bind:value={time} />
|
||||
<div class="h-4" />
|
||||
<div class="flex items-center">
|
||||
<p class="ml-4 mr-4">At Pity:</p>
|
||||
<Input type="number" bind:value={pity} />
|
||||
</div>
|
||||
{#if isEdit}
|
||||
<div class="flex mt-32">
|
||||
<div class="flex-1 flex mr-2 items-end">
|
||||
<Button className="flex-1" on:click={skip}>Cancel</Button>
|
||||
</div>
|
||||
<div class="flex-1 flex flex-col ml-2">
|
||||
<Button className="flex-1" color="red" on:click={deleteDetail}>Delete</Button>
|
||||
<Button className="flex-1 mt-2" {disabled} on:click={edit}>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex mt-32">
|
||||
<Button className="flex-1 mr-2" color="red" on:click={skip}>Skip</Button>
|
||||
<Button className="flex-1 ml-2" {disabled} on:click={add}>Add</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
|
@ -11,44 +11,62 @@
|
|||
Press
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center">+1</b>
|
||||
when you get
|
||||
<span class="inline-flex items-center">3
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>3
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
</p>
|
||||
<p class="mb-2">
|
||||
Press
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center">Get 4
|
||||
<Icon path={mdiStar} size={0.7} /></b>
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center"
|
||||
>Get 4
|
||||
<Icon path={mdiStar} size={0.7} /></b
|
||||
>
|
||||
when you get
|
||||
<span class="inline-flex items-center">4
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>4
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
</p>
|
||||
<p class="mb-2">
|
||||
Press
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center">Get 5
|
||||
<Icon path={mdiStar} size={0.7} /></b>
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center"
|
||||
>Get 5
|
||||
<Icon path={mdiStar} size={0.7} /></b
|
||||
>
|
||||
when you get
|
||||
<span class="inline-flex items-center">5
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>5
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
</p>
|
||||
<p class="text-gray-400">
|
||||
It will automatically add the lifetime pulls,
|
||||
<span class="inline-flex items-center">5
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>5
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
and
|
||||
<span class="inline-flex items-center">4
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>4
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
pity
|
||||
</p>
|
||||
<p class="text-gray-400">
|
||||
When the
|
||||
<span class="inline-flex items-center">4
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>4
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
pity reach 10, it will automatically reset to 0
|
||||
</p>
|
||||
<p class="text-gray-400">
|
||||
When the
|
||||
<span class="inline-flex items-center">5
|
||||
<Icon path={mdiStar} size={0.7} /></span>
|
||||
<span class="inline-flex items-center"
|
||||
>5
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
pity reach 90, it will automatically reset to 0
|
||||
</p>
|
||||
</div>
|
||||
|
@ -56,15 +74,28 @@
|
|||
For when you do 10 pulls Wish, press the
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center">+10</b>
|
||||
button,
|
||||
<span class="text-gray-400">but the pity counter won't be accurate, because there is no way to tell when the drop
|
||||
occur (maybe you got it on the 1st or even the 10th). To make the counter still accurate, you need to check it on
|
||||
the history table and add it 1 by 1 like you do 1 pull Wish.</span>
|
||||
<span class="text-gray-400"
|
||||
>but the pity counter won't be accurate, because there is no way to tell when the drop occur (maybe you got it on
|
||||
the 1st or even the 10th). To make the counter still accurate, you need to check it on the history table and add
|
||||
it 1 by 1 like you do 1 pull Wish.</span
|
||||
>
|
||||
</div>
|
||||
<div class="text-white p-2 bg-background rounded-xl mt-4">
|
||||
You can also press
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center"><Icon
|
||||
path={mdiPencil}
|
||||
size={0.7} /></b>
|
||||
<b class="rounded-lg px-2 py-1 border-white border inline-flex items-center"><Icon path={mdiPencil} size={0.7} /></b
|
||||
>
|
||||
button to edit the values manually!
|
||||
</div>
|
||||
<div class="text-white p-2 bg-background rounded-xl mt-4">
|
||||
Press the arrow on the bottom to see your pulls detail. A popup will show when you get <span
|
||||
class="inline-flex items-center"
|
||||
>5
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>
|
||||
or
|
||||
<span class="inline-flex items-center"
|
||||
>4
|
||||
<Icon path={mdiStar} size={0.7} /></span
|
||||
>. Or you can add or edit the table manually.
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { mdiPencil, mdiStar } from '@mdi/js';
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { mdiPencil, mdiStar, mdiChevronDown } from '@mdi/js';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||
|
||||
import Button from '../../components/Button.svelte';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import Input from '../../components/Input.svelte';
|
||||
import AddModal from '../../components/WishCounterAddModal.svelte';
|
||||
|
||||
import { readSave, updateSave, fromRemote } from '../../stores/saveManager';
|
||||
import { characters } from '../../data/characters';
|
||||
import dayjs from 'dayjs';
|
||||
import { weaponList } from '../../data/weaponList';
|
||||
|
||||
export let id = '';
|
||||
export let name = '';
|
||||
|
||||
let isEdit = false;
|
||||
let isDetailOpen = false;
|
||||
|
||||
let total = 0;
|
||||
let legendary = 0;
|
||||
let rare = 0;
|
||||
let pulls = [];
|
||||
|
||||
let totalEdit = 0;
|
||||
let legendaryEdit = 0;
|
||||
|
@ -25,11 +35,76 @@
|
|||
$: if ($fromRemote) {
|
||||
readLocalData();
|
||||
}
|
||||
$: sortedPull = pulls.sort((a, b) => b.time - a.time);
|
||||
|
||||
onMount(() => {
|
||||
readLocalData();
|
||||
});
|
||||
|
||||
function toggleDetail() {
|
||||
isDetailOpen = !isDetailOpen;
|
||||
}
|
||||
|
||||
function openAddModal(pity) {
|
||||
openModal(
|
||||
AddModal,
|
||||
{
|
||||
pity,
|
||||
skip: closeModal,
|
||||
addPullDetail,
|
||||
},
|
||||
{
|
||||
closeButton: false,
|
||||
closeOnOuterClick: false,
|
||||
styleWindow: { background: '#25294A', width: '400px' },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function openEditModal(index, type, name, time, pity) {
|
||||
openModal(
|
||||
AddModal,
|
||||
{
|
||||
isEdit: true,
|
||||
editType: type,
|
||||
editName: name,
|
||||
editTime: time,
|
||||
pity,
|
||||
skip: closeModal,
|
||||
editPullDetail: (pull) => editPullDetail(index, pull),
|
||||
deletePullDetail: () => deletePullDetail(index),
|
||||
},
|
||||
{
|
||||
closeButton: false,
|
||||
closeOnOuterClick: false,
|
||||
styleWindow: { background: '#25294A', width: '400px' },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function addPullDetail(newPull) {
|
||||
pulls = [...pulls, newPull];
|
||||
closeModal();
|
||||
saveData();
|
||||
}
|
||||
|
||||
function editPullDetail(index, updatePull) {
|
||||
const updated = sortedPull;
|
||||
updated[index] = updatePull;
|
||||
pulls = updated;
|
||||
|
||||
closeModal();
|
||||
saveData();
|
||||
}
|
||||
|
||||
function deletePullDetail(index) {
|
||||
sortedPull.splice(index, 1);
|
||||
pulls = sortedPull;
|
||||
|
||||
closeModal();
|
||||
saveData();
|
||||
}
|
||||
|
||||
function toggleEdit() {
|
||||
isEdit = !isEdit;
|
||||
if (isEdit) {
|
||||
|
@ -56,6 +131,7 @@
|
|||
total = counterData.total;
|
||||
legendary = counterData.legendary;
|
||||
rare = counterData.rare;
|
||||
pulls = counterData.pulls || [];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +140,7 @@
|
|||
total,
|
||||
legendary,
|
||||
rare,
|
||||
pulls,
|
||||
});
|
||||
|
||||
updateSave(path, data);
|
||||
|
@ -76,6 +153,7 @@
|
|||
|
||||
rare += val;
|
||||
if (rare >= 10) {
|
||||
openAddModal(rare);
|
||||
rare = 0;
|
||||
} else if (rare < 0) {
|
||||
rare = 9;
|
||||
|
@ -83,6 +161,7 @@
|
|||
|
||||
legendary += val;
|
||||
if (legendary >= 90) {
|
||||
openAddModal(legendary);
|
||||
legendary = 0;
|
||||
rare = 0;
|
||||
} else if (legendary < 0) {
|
||||
|
@ -93,6 +172,8 @@
|
|||
}
|
||||
|
||||
function getLegendary() {
|
||||
openAddModal(legendary);
|
||||
|
||||
total += 1;
|
||||
legendary = 0;
|
||||
rare = 0;
|
||||
|
@ -100,6 +181,8 @@
|
|||
}
|
||||
|
||||
function getRare() {
|
||||
openAddModal(rare);
|
||||
|
||||
total += 1;
|
||||
legendary += 1;
|
||||
rare = 0;
|
||||
|
@ -116,14 +199,20 @@
|
|||
</div>
|
||||
<div class="flex flex-col w-full">
|
||||
<div
|
||||
class={`${isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'} rounded-xl flex`}>
|
||||
class={`${
|
||||
isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'
|
||||
} rounded-xl flex`}
|
||||
>
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">Lifetime Pulls</span>
|
||||
{#if isEdit}
|
||||
<Input type="number" min={1} bind:value={totalEdit} />
|
||||
{:else}<span class="font-black text-3xl text-white ml-4">{total}</span>{/if}
|
||||
</div>
|
||||
<div
|
||||
class={`${isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'} rounded-xl flex`}>
|
||||
class={`${
|
||||
isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'
|
||||
} rounded-xl flex`}
|
||||
>
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
||||
5
|
||||
<Icon path={mdiStar} size={0.75} className="mb-1" />
|
||||
|
@ -135,7 +224,10 @@
|
|||
{:else}<span class="font-black text-3xl text-legendary-from ml-4">{legendary}</span>{/if}
|
||||
</div>
|
||||
<div
|
||||
class={`${isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'} rounded-xl flex`}>
|
||||
class={`${
|
||||
isEdit ? 'bg-item flex-col py-2' : 'bg-background flex-row items-center justify-center mb-2 p-4'
|
||||
} rounded-xl flex`}
|
||||
>
|
||||
<span class="text-gray-200 whitespace-no-wrap flex-1">
|
||||
4
|
||||
<Icon path={mdiStar} size={0.75} className="mb-1" />
|
||||
|
@ -166,4 +258,47 @@
|
|||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if isDetailOpen}
|
||||
<div transition:slide class="mt-4 text-white">
|
||||
<table class="w-full">
|
||||
<tr>
|
||||
<th class="border-b border-gray-700 text-left pl-2">Name</th>
|
||||
<th class="border-b border-gray-700 text-left pl-2">Time</th>
|
||||
<th class="border-b border-gray-700 text-center">Pity</th>
|
||||
</tr>
|
||||
{#each sortedPull as pull, index}
|
||||
<tr on:click={() => openEditModal(index, pull.type, pull.id, pull.time, pull.pity)}>
|
||||
{#if pull.type === 'character'}
|
||||
<td
|
||||
class={`border-b border-gray-700 py-1 pl-2 font-semibold ${
|
||||
characters[pull.id].rarity === 5 ? 'text-legendary-from' : 'text-rare-from'
|
||||
}`}>{characters[pull.id].name}</td
|
||||
>
|
||||
{:else}
|
||||
<td
|
||||
class={`border-b border-gray-700 py-1 pl-2 font-semibold ${
|
||||
weaponList[pull.id].rarity === 5 ? 'text-legendary-from' : 'text-rare-from'
|
||||
}`}>{weaponList[pull.id].name}</td
|
||||
>
|
||||
{/if}
|
||||
<td class="border-b border-gray-700 py-1 px-2">{dayjs.unix(pull.time).format('YYYY-MM-DD HH:mm')}</td>
|
||||
<td class="text-center border-b border-gray-700 py-1">{pull.pity}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<div class="bg-background rounded-xl px-4 mr-2 flex items-center">
|
||||
<span>Click the list to edit or delete</span>
|
||||
</div>
|
||||
<Button size="sm" className="w-16" on:click={() => openAddModal(0)}>Add</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex justify-center items-end h-8 mt-2" on:click={toggleDetail}>
|
||||
<Icon
|
||||
path={mdiChevronDown}
|
||||
color="white"
|
||||
className={`duration-100 ease-in ${isDetailOpen ? 'transform rotate-180' : ''}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import dayjs from 'dayjs';
|
|||
import { writable } from 'svelte/store';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { synced, saveId, localModified, lastSyncTime } from './dataSync';
|
||||
import { synced, saveId, localModified, lastSyncTime, driveSignedIn } from './dataSync';
|
||||
import { pushToast } from './toast';
|
||||
|
||||
export const updateTime = writable(null);
|
||||
|
@ -13,11 +13,16 @@ export const UPDATE_TIME_KEY = 'update-time';
|
|||
let pendingQueue = [];
|
||||
let queueSave = true;
|
||||
let saveFileId = '';
|
||||
let signedIn = false;
|
||||
|
||||
saveId.subscribe((val) => {
|
||||
saveFileId = val;
|
||||
});
|
||||
|
||||
driveSignedIn.subscribe((val) => {
|
||||
signedIn = val;
|
||||
});
|
||||
|
||||
const saveToRemote = debounce(() => {
|
||||
saveData(getLocalSaveJson());
|
||||
}, 5000);
|
||||
|
@ -38,10 +43,10 @@ async function saveData(data) {
|
|||
synced.set(true);
|
||||
localModified.set(false);
|
||||
|
||||
pushToast('Data has been synced!')
|
||||
pushToast('Data has been synced!');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
pushToast('Error when uploading your data!', 'error')
|
||||
pushToast('Error when uploading your data!', 'error');
|
||||
synced.set(true);
|
||||
}
|
||||
}
|
||||
|
@ -81,10 +86,13 @@ export const updateSave = (key, data, isFromRemote) => {
|
|||
localStorage.setItem(key, data);
|
||||
|
||||
if (!isFromRemote) {
|
||||
const currentTime = dayjs().toISOString();
|
||||
const currentTime = dayjs();
|
||||
updateTime.set(currentTime);
|
||||
localStorage.setItem(UPDATE_TIME_KEY, currentTime);
|
||||
saveToRemote();
|
||||
localStorage.setItem(UPDATE_TIME_KEY, currentTime.toISOString());
|
||||
|
||||
if (signedIn) {
|
||||
saveToRemote();
|
||||
}
|
||||
} else {
|
||||
fromRemote.set(true);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue