Archiving a currency strands shop listings priced in it: unbuyable, unflagged, and uneditable
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 2h 52m
- Merged PRs (30d)
- 85
Description
Report
From Discord (Neo the Baka):
archiving a currency makes all shop purchases involving it impossible to use, the shop keeps the item and does not have a method to either remove or warn about unobtainable items
trying to update a shop entry after removing the archived currency still throws an errror
Archiving a currency is allowed with no regard for shop listings priced in it. Three separate problems fall out of that.
1. The listing stays visible and looks buyable
Nothing filters or flags a listing whose price names an archived currency. It renders in the shop grid with its price, undimmed, and the buyer can add it to the cart. The failure only arrives at checkout, from the ledger — CurrencyLedgerService refuses any transaction in an archived currency (apps/backend/src/currencies/currency-ledger.service.ts:196, "X is archived and takes no new transactions"). The buyer gets a toast that reads like a bug, having been shown a price they were never able to pay.
ShopService.assertPricesBelongTo (apps/backend/src/shop/shop.service.ts:279) already refuses to create a price in an archived currency, with the reasoning written down at :275-277 — "an option could name a currency nobody can be charged in, and the listing would look buyable while never being so". Archiving after the fact walks straight around that check and produces exactly the state it was written to prevent.
2. Such a listing cannot be edited at all
updateShopItem re-validates the whole price array whenever prices are present (shop.service.ts:220-222), and the admin form always sends them — toInput() (apps/frontend/src/pages/CommunityShopAdminPage.tsx:386-399) includes prices unconditionally, whatever the admin actually changed. So one archived component makes every save through the edit dialog fail with "X is archived and cannot be charged": the name, the description, the stock, the per-member cap, all of it. The listing is frozen.
3. The archived currency is invisible in the picker, so it cannot be removed
useGetCurrenciesQuery on this page is called without includeArchived (CommunityShopAdminPage.tsx:325-329), which defaults to false server-side (apps/backend/src/currencies/currencies.resolver.ts:78). But open() seeds the draft prices straight from the item, archived currency ids included (:368-377). The <select> at :707-714 therefore has a value with no matching <option> — it renders with nothing selected, naming neither the currency that is set nor the fact that it is archived. The admin is asked to fix a row that will not say what is wrong with it.
This is the reporter's second sentence: they cleared what looked like the offending row and the save still failed, because a <select> showing nothing is indistinguishable from one they successfully changed, and because any other price option still holding the archived currency blocks the save just the same.
Fix
Ranked:
- Make the archived currency visible and fixable in the admin form. Pass
includeArchived: trueto the currency query on this page, and mark archived options ("Festival Token (archived)"). A price component whose currency is archived should be called out in the dialog and block submit locally with a message that names it. - Do not send
priceswhen they were not touched.toInput()should omitpricesunless the admin edited them, so a listing priced in an archived currency can still be renamed, restocked, or corrected in every other respect. - Warn in the admin table. A listing with an unspendable price should be flagged in the row (
:528-556), next to the existing· hiddenmarker, so staff can find them without opening each one. - Warn at archive time.
CurrenciesService.update(apps/backend/src/currencies/currencies.service.ts:88) should say how many live shop listings are priced in the currency being archived. Whether to block, auto-hide those listings, or just warn is a product call — but archiving should not be silent about it. - Hide or mark the listing member-side. A listing that cannot be paid for should not be offered at full price with a working "+" button. Simplest is to treat "any price component in an archived currency" the same as sold out, with a reason.
Note
There is an escape hatch today, but it is not discoverable: the hide/show toggle in the admin table sends only { active } and no prices (CommunityShopAdminPage.tsx:430-434), so it is not caught by the validation in (2). Staff can hide an unbuyable listing — they just cannot edit it, and nothing tells them that hiding is the one action that will work.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ShopService.assertPricesBelongTo and updateShopItem, then trace CommunityShopAdminPage.tsx at the cited query, toInput, picker, table, and hide-toggle locations. Check the currency resolver and CurrenciesService.update, and inspect existing shop and currency tests if available. Done means archived-currency listings are identifiable and staff can recover or safely manage them without misleading buyers, with the product choice on warning, hiding, or blocking resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100