Add wish tally submit

pull/1/head
Made Baruna 2021-03-29 05:25:08 +08:00
parent 6ffdcbba0c
commit da425bf0ac
9 changed files with 182 additions and 22 deletions

View File

@ -1,3 +1,3 @@
GOOGLE_DRIVE_CLIENT_ID=
GOOGLE_DRIVE_API_KEY=
CORS_HOST=
API_HOST=http://localhost:3001

View File

@ -49,6 +49,7 @@
id: name.id,
time: dayjs(time).unix(),
pity,
manualInput: true,
};
addPullDetail(pull);
@ -60,6 +61,7 @@
id: name.id,
time: dayjs(time).unix(),
pity,
manualInput: true,
};
editPullDetail(pull);

View File

@ -1,18 +1,20 @@
<script>
import { t } from 'svelte-i18n';
import { mdiLoading, mdiPencil, mdiStar } from '@mdi/js';
import { mdiCheckCircleOutline, mdiLoading, mdiPencil, mdiStar } from '@mdi/js';
import Icon from './Icon.svelte';
import Button from './Button.svelte';
import Checkbox from '../components/Checkbox.svelte';
import { exportToExcel } from '../functions/export';
import { submitWishTally } from '../functions/wishTally';
import { pushToast } from '../stores/toast';
export let setManualInput;
export let settings;
let loadingExport = false;
let wishTallySubmitted = false;
let enableManual = settings.manualInput;
@ -20,6 +22,12 @@
setManualInput(enableManual);
}
function submitWish() {
submitWishTally();
pushToast($t('wish.help.wishTallyThankyou'));
wishTallySubmitted = true;
}
async function exportFile() {
loadingExport = true;
await exportToExcel();
@ -43,6 +51,21 @@
</Button>
<!-- <Button disabled={loadingExport}>{$t('wish.help.import')}</Button> -->
</div>
<h1 class="font-display text-white text-xl mt-8 mb-2">{$t('wish.help.wishTallyTitle')}</h1>
<div class="text-white p-2 bg-background rounded-xl">
<p class="mb-1">{$t('wish.help.wishTally')}</p>
<p class="mb-1">
{$t('wish.help.wishTallyCollected.0')} 5<Icon size={0.8} path={mdiStar} className="mb-1" />
{$t('wish.help.wishTallyCollected.1')} 4<Icon size={0.8} path={mdiStar} className="mb-1" />
{$t('wish.help.wishTallyCollected.2')}
</p>
<Button className="mr-2" disabled={wishTallySubmitted} on:click={submitWish}>
{#if wishTallySubmitted}
<Icon path={mdiCheckCircleOutline} size={0.8} />
{/if}
{$t('wish.help.wishTallySubmit')}
</Button>
</div>
<h1 class="font-display text-white text-xl mt-8 mb-2">{$t('wish.help.manualTitle')}</h1>
<div class="text-white p-2 bg-background rounded-xl">
<div class="py-2 pl-4">

View File

@ -1,8 +1,9 @@
<script>
import { t } from 'svelte-i18n';
import { mdiClose, mdiDownload, mdiHelpCircle, mdiInformation, mdiLoading } from '@mdi/js';
import { mdiChevronDown, mdiClose, mdiDownload, mdiHelpCircle, mdiInformation, mdiLoading, mdiStar } from '@mdi/js';
import { onMount } from 'svelte';
import { slide } from 'svelte/transition';
import dayjs from 'dayjs';
import { pushToast } from '../stores/toast';
@ -15,6 +16,7 @@
import { characters } from '../data/characters';
import { readSave, updateSave } from '../stores/saveManager';
import { getAccountPrefix } from '../stores/account';
import { submitWishTally } from '../functions/wishTally';
export let processFirstTimePopup;
export let closeModal;
@ -30,6 +32,9 @@
let generatedTextInput = '';
let genshinLink = '';
let wishTallyInfoExpanded = false;
let wishTallyChecked = true;
let types = {
100: {
name: "Beginners' Wish",
@ -166,7 +171,7 @@
try {
const res = await fetchRetry(
__paimon.env.CORS_HOST,
`${__paimon.env.API_HOST}/corsproxy`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -297,6 +302,10 @@
return new Promise((resolve) => setTimeout(resolve, ms));
}
function toggleWishTallyInfo() {
wishTallyInfoExpanded = !wishTallyInfoExpanded;
}
function toggleFaqs(show) {
showFaq = show;
}
@ -378,6 +387,11 @@
calculatingPity = false;
pushToast($t('wish.import.success'));
if (wishTallyChecked) {
submitWishTally();
}
closeModal();
}
@ -458,7 +472,7 @@
{#each Object.entries(types) as [code, type]}
<tr>
<td class="border-b border-gray-700 py-1">
<span class="text-white mr-2 whitespace-no-wrap">{type.name} Banner</span>
<span class="text-white mr-2">{type.name} Banner</span>
</td>
<td class="border-b border-gray-700 py-1">
{#if wishes[code] !== undefined}
@ -473,6 +487,29 @@
</tr>
{/each}
</table>
<div class="mt-4 mb-2 rounded-xl px-2 py-2 md:px-4 md:py-2 bg-black bg-opacity-25 text-gray-400">
<div class="pl-1 flex flex-col md:flex-row items-center">
<Checkbox bind:checked={wishTallyChecked}>
<p class="ml-1">{$t('wish.import.wishTallyCheck')}</p>
</Checkbox>
<div
class="w-full py-1 md:py-0 md:w-12 md:px-3 flex items-center justify-center cursor-pointer"
on:click={toggleWishTallyInfo}
>
<Icon path={mdiChevronDown} />
</div>
</div>
{#if wishTallyInfoExpanded}
<div class="pt-1" transition:slide>
<p class="mb-1">{$t('wish.import.wishTally')}</p>
<p>
{$t('wish.import.wishTallyCollected.0')} 5<Icon size={0.8} path={mdiStar} className="mb-1" />
{$t('wish.import.wishTallyCollected.1')} 4<Icon size={0.8} path={mdiStar} className="mb-1" />
{$t('wish.import.wishTallyCollected.2')}
</p>
</div>
{/if}
</div>
<p class="mt-4">{$t('wish.import.importNotice1')}</p>
<p>{$t('wish.import.importNotice2')}</p>
<p class="font-semibold">{$t('wish.import.saveData')}</p>

View File

@ -67,7 +67,7 @@ export function process(id) {
image,
total: 0,
legendary: [],
rarePity: [0,0,0,0,0,0,0,0,0,0],
rarePity: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
rare: {
character: [],
weapon: [],
@ -89,6 +89,7 @@ export function process(id) {
let striped = false;
let startBanner = false;
let currentBannerIndex = -1;
let hasManualInput = false;
for (let i = 0; i < pullData.length; i++) {
const pull = pullData[i];
@ -154,6 +155,10 @@ export function process(id) {
newPull.end = true;
}
if (pull.manualInput === true) {
hasManualInput = true;
}
newPull.striped = striped;
startBanner = false;
@ -163,5 +168,6 @@ export function process(id) {
return {
pulls: currentPulls,
banner: selectedBanners,
}
hasManualInput,
};
}

View File

@ -0,0 +1,61 @@
import { process } from './wish';
const bannerCategories = ['beginners', 'standard', 'character-event', 'weapon-event'];
async function sendWish(data) {
try {
await fetch(`${__paimon.env.API_HOST}/wish`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
} catch (err) {
console.error(err);
}
}
export async function submitWishTally() {
let prefixId = 0;
for (const id of bannerCategories) {
prefixId += 100000;
const data = process(id);
if (data === null) continue;
if (data.hasManualInput) continue;
console.log('processing wish tally', id);
const { pulls, banner } = data;
const firstFivePulls = pulls.slice(0, 5).map((e) => [e.time.toString(), e.id, e.type, e.pity, e.group === 'group']);
for (let i = banner.length - 1; i >= Math.max(banner.length - 2, 0); i--) {
const total = banner[i].total;
if (total === 0) continue;
const rarePity = banner[i].rarePity;
const legendaryCount = banner[i].legendary.length;
const rareCount = banner[i].rare.character.length + banner[i].rare.weapon.length;
const legendaryPulls = banner[i].legendary.map((e) => [
e.time.toString(),
e.id,
e.type,
e.pity,
e.group === 'group',
]);
console.log(legendaryPulls);
console.log(rarePity);
console.log(legendaryCount, rareCount, total);
await sendWish({
firstPulls: firstFivePulls,
legendaryPulls,
rarePulls: rarePity,
banner: prefixId + i + 1,
total,
legendary: legendaryCount,
rare: rareCount,
});
}
}
}

View File

@ -48,6 +48,9 @@
"timeout": "Connection timeout, please wait a moment and try again later",
"invalidData": "Invalid data returned from API, try again later",
"success": "Import success 😀!",
"wishTallyCheck": "Submit pity for global wish tally",
"wishTally": "We are doing a global wish tally! You can submit your wish tally to participate. All pity data will be aggregated to know what is the average pity of paimon.moe users.",
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
"faqs": {
"title": "Import Wish History FAQ",
"q1": "How does it work?",
@ -110,6 +113,11 @@
"exporting": "Exporting...",
"import": "Import",
"exportFinish": "Export success, please wait until the browser download the file!",
"wishTallyTitle": "Submit Wish Tally",
"wishTally": "We are doing a global wish tally! You can submit your wish tally to participate. All pity data will be aggregated to know what is the average pity of paimon.moe users.",
"wishTallyCollected": ["What will be collected:", "and", "pity from your wish history"],
"wishTallySubmit": "Submit Wish Tally",
"wishTallyThankyou": "Thankyou for participating!",
"manualTitle": "Manual Input Setting",
"enableManual": "Enable Manual Input",
"notice": "Using Auto Import and manual input together is not recommended as it still requires some more testing!",

View File

@ -48,6 +48,9 @@
"timeout": "Connection timeout, tunggu sebentar dan coba lagi nanti",
"invalidData": "Invalid data dikembalikan dari API, coba lagi nanti",
"success": "Import berhasil 😀!",
"wishTallyCheck": "Submit pity untuk perhitungan pity global",
"wishTally": "Kita sedang melakukan perhitungan pity global! Kamu bisa mensubmit pity mu untuk berpartisipasi. Semua data pity akan dikumpulkan untuk mengetahui berapa pity rata-rata pengguna paimon.moe.",
"wishTallyCollected": ["Yang dikumpulkan:", "dan", "pity dari riwayat wish mu"],
"faqs": {
"title": "Import Riwayat Wish FAQS",
"q1": "Cara kerjanya gimana?",
@ -110,6 +113,11 @@
"exporting": "Sedang meng-export...",
"import": "Import",
"exportFinish": "Export berhasil, harap tunggu sampai file nya sudah ter-download!",
"wishTallyTitle": "Submit Perhitungan Pity Wish",
"wishTally": "Kita sedang melakukan perhitungan pity global! Kamu bisa mensubmit pity mu untuk berpartisipasi. Semua data pity akan dikumpulkan untuk mengetahui berapa pity rata-rata pengguna paimon.moe.",
"wishTallyCollected": ["Yang dikumpulkan:", "dan", "pity dari riwayat wish mu"],
"wishTallySubmit": "Submit Perhitungan Pity Wish",
"wishTallyThankyou": "Terimakasih sudah berpartisipasi!",
"manualTitle": "Pengaturan Manual Input",
"enableManual": "Nyalakan Manual Input",
"notice": "Menggunakan Import Otomatis dan Manual Input secara bersamaan tidak direkomendasikan karena belum stabil, dan masih perlu di testing!",

View File

@ -39,24 +39,17 @@
let rareEdit = 0;
let showRarity = [true, true, false];
let sortedPull = [];
$: path = `wish-counter-${id}`;
$: if ($fromRemote) {
readLocalData();
}
$: sortedPull = pulls
.slice()
.filter((e) => {
if (e.type === 'character') {
return showRarity[5 - characters[e.id].rarity];
} else if (e.type === 'weapon') {
return showRarity[5 - weaponList[e.id].rarity];
}
})
.reverse();
$: showRarity, pulls, filterRarity();
onMount(() => {
readLocalData();
filterRarity();
});
function toggleDetail() {
@ -67,6 +60,27 @@
showRarity[index] = !showRarity[index];
}
function filterRarity() {
const sorted = [];
const reversedPulls = pulls.slice();
for (let i = reversedPulls.length - 1; i >= 0; i--) {
const e = reversedPulls[i];
if (e.type === 'character' && showRarity[5 - characters[e.id].rarity]) {
sorted.push({
index: i,
...e,
});
} else if (e.type === 'weapon' && showRarity[5 - weaponList[e.id].rarity]) {
sorted.push({
index: i,
...e,
});
}
}
sortedPull = sorted;
}
function openAddModal(pity) {
openModal(
AddModal,
@ -120,7 +134,7 @@
}
function editPullDetail(index, updatePull) {
const updated = sortedPull;
const updated = pulls.slice();
updated[index] = updatePull;
pulls = updated;
@ -129,8 +143,9 @@
}
function deletePullDetail(index) {
sortedPull.splice(index, 1);
pulls = sortedPull;
const updated = pulls.slice();
updated.splice(index, 1);
pulls = updated;
closeModal();
saveData();
@ -361,8 +376,8 @@
<th class="border-b border-gray-700 text-gray-400 font-display text-left pl-2">Time</th>
<th class="border-b border-gray-700 text-gray-400 font-display text-right">Pity</th>
</tr>
{#each sortedPull as pull, index}
<tr on:click={manualInput ? () => openEditModal(index, pull.type, pull.id, pull.time, pull.pity) : () => {}}>
{#each sortedPull as pull}
<tr on:click={manualInput ? () => openEditModal(pull.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 ${