mirror of
https://github.com/System-End/scraps.git
synced 2026-04-20 00:25:18 +00:00
non buyer refinery
This commit is contained in:
parent
fa338e9229
commit
2a0a9ec79b
2 changed files with 153 additions and 7 deletions
|
|
@ -1806,6 +1806,84 @@ admin.delete("/shop/items/:id", async ({ params, headers, status }) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Reset refinery orders for users who haven't won/purchased any item
|
||||
admin.post("/shop/reset-non-buyer-refinery", async ({ headers, status }) => {
|
||||
try {
|
||||
const user = await requireAdmin(headers as Record<string, string>);
|
||||
if (!user) {
|
||||
return status(401, { error: "Unauthorized" });
|
||||
}
|
||||
|
||||
// Find user+item combos that have refinery orders but no luck_win/purchase shop orders
|
||||
const refineryUsers = await db
|
||||
.select({
|
||||
userId: refineryOrdersTable.userId,
|
||||
shopItemId: refineryOrdersTable.shopItemId,
|
||||
})
|
||||
.from(refineryOrdersTable)
|
||||
.groupBy(refineryOrdersTable.userId, refineryOrdersTable.shopItemId);
|
||||
|
||||
const buyers = await db
|
||||
.select({
|
||||
userId: shopOrdersTable.userId,
|
||||
shopItemId: shopOrdersTable.shopItemId,
|
||||
})
|
||||
.from(shopOrdersTable)
|
||||
.where(
|
||||
or(
|
||||
eq(shopOrdersTable.orderType, "purchase"),
|
||||
eq(shopOrdersTable.orderType, "luck_win"),
|
||||
),
|
||||
)
|
||||
.groupBy(shopOrdersTable.userId, shopOrdersTable.shopItemId);
|
||||
|
||||
const buyerSet = new Set(buyers.map((b) => `${b.userId}-${b.shopItemId}`));
|
||||
const toReset = refineryUsers.filter(
|
||||
(r) => !buyerSet.has(`${r.userId}-${r.shopItemId}`),
|
||||
);
|
||||
|
||||
let deletedOrders = 0;
|
||||
let deletedHistory = 0;
|
||||
for (const { userId, shopItemId } of toReset) {
|
||||
const deleted = await db
|
||||
.delete(refineryOrdersTable)
|
||||
.where(
|
||||
and(
|
||||
eq(refineryOrdersTable.userId, userId),
|
||||
eq(refineryOrdersTable.shopItemId, shopItemId),
|
||||
),
|
||||
)
|
||||
.returning({ id: refineryOrdersTable.id });
|
||||
deletedOrders += deleted.length;
|
||||
|
||||
const historyDeleted = await db
|
||||
.delete(refinerySpendingHistoryTable)
|
||||
.where(
|
||||
and(
|
||||
eq(refinerySpendingHistoryTable.userId, userId),
|
||||
eq(refinerySpendingHistoryTable.shopItemId, shopItemId),
|
||||
),
|
||||
)
|
||||
.returning({ id: refinerySpendingHistoryTable.id });
|
||||
deletedHistory += historyDeleted.length;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[ADMIN] Reset non-buyer refinery: ${toReset.length} user-item combos, ${deletedOrders} orders, ${deletedHistory} history entries deleted`,
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
resetCount: toReset.length,
|
||||
deletedOrders,
|
||||
deletedHistory,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("[ADMIN] Failed to reset non-buyer refinery:", err);
|
||||
return status(500, { error: "Failed to reset refinery orders" });
|
||||
}
|
||||
});
|
||||
|
||||
// News admin endpoints (admin only)
|
||||
admin.get("/news", async ({ headers, status }) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@
|
|||
let formMonetaryValue = $state(0);
|
||||
let formError = $state<string | null>(null);
|
||||
let errorModal = $state<string | null>(null);
|
||||
let resettingRefinery = $state(false);
|
||||
let showResetConfirm = $state(false);
|
||||
|
||||
const PHI = (1 + Math.sqrt(5)) / 2;
|
||||
const SCRAPS_PER_HOUR = PHI * 10;
|
||||
|
|
@ -441,6 +443,29 @@
|
|||
deleteConfirmId = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function resetNonBuyerRefinery() {
|
||||
resettingRefinery = true;
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/admin/shop/reset-non-buyer-refinery`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok && data.success) {
|
||||
errorModal = `Reset ${data.resetCount} user-item combos: ${data.deletedOrders} refinery orders and ${data.deletedHistory} history entries deleted`;
|
||||
await fetchItems();
|
||||
} else {
|
||||
errorModal = data.error || 'Failed to reset refinery orders';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to reset refinery:', e);
|
||||
errorModal = 'Failed to reset refinery orders';
|
||||
} finally {
|
||||
resettingRefinery = false;
|
||||
showResetConfirm = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
@ -453,13 +478,22 @@
|
|||
<h1 class="mb-2 text-4xl font-bold md:text-5xl">{$t.nav.shop}</h1>
|
||||
<p class="text-lg text-gray-600">{$t.admin.manageShopItemsAndInventory}</p>
|
||||
</div>
|
||||
<button
|
||||
onclick={openCreateModal}
|
||||
class="flex cursor-pointer items-center gap-2 rounded-full bg-black px-6 py-3 font-bold text-white transition-all duration-200 hover:bg-gray-800"
|
||||
>
|
||||
<Plus size={20} />
|
||||
{$t.admin.addItem}
|
||||
</button>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
onclick={() => (showResetConfirm = true)}
|
||||
disabled={resettingRefinery}
|
||||
class="cursor-pointer rounded-full border-4 border-red-600 px-4 py-2 font-bold text-red-600 transition-all duration-200 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{resettingRefinery ? 'resetting...' : 'reset non-buyer refinery'}
|
||||
</button>
|
||||
<button
|
||||
onclick={openCreateModal}
|
||||
class="flex cursor-pointer items-center gap-2 rounded-full bg-black px-6 py-3 font-bold text-white transition-all duration-200 hover:bg-gray-800"
|
||||
>
|
||||
<Plus size={20} />
|
||||
{$t.admin.addItem}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-8 rounded-2xl border-4 border-black p-4">
|
||||
|
|
@ -1091,6 +1125,40 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showResetConfirm}
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
|
||||
onclick={(e) => e.target === e.currentTarget && (showResetConfirm = false)}
|
||||
onkeydown={(e) => e.key === 'Escape' && (showResetConfirm = false)}
|
||||
role="dialog"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div class="w-full max-w-md rounded-2xl border-4 border-black bg-white p-6">
|
||||
<h2 class="mb-4 text-2xl font-bold">reset non-buyer refinery</h2>
|
||||
<p class="mb-6 text-gray-600">
|
||||
this will delete all refinery orders and spending history for users who have never won or
|
||||
purchased an item, refunding their scraps. this cannot be undone.
|
||||
</p>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
onclick={() => (showResetConfirm = false)}
|
||||
disabled={resettingRefinery}
|
||||
class="flex-1 cursor-pointer rounded-full border-4 border-black px-4 py-2 font-bold transition-all duration-200 hover:border-dashed disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
cancel
|
||||
</button>
|
||||
<button
|
||||
onclick={resetNonBuyerRefinery}
|
||||
disabled={resettingRefinery}
|
||||
class="flex-1 cursor-pointer rounded-full border-4 border-black bg-red-600 px-4 py-2 font-bold text-white transition-all duration-200 hover:border-dashed disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{resettingRefinery ? 'resetting...' : 'reset'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if errorModal}
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue