diff --git a/backend/core/src/core/actions/gift.py b/backend/core/src/core/actions/gift.py index 0f134d7b..05194c7d 100644 --- a/backend/core/src/core/actions/gift.py +++ b/backend/core/src/core/actions/gift.py @@ -19,7 +19,6 @@ from core.services.gift.collection import GiftCollectionService from core.services.gift.item import GiftUniqueService from core.services.superredis import RedisService -from core.settings import core_settings from core.utils.cache import cached_dto_result @@ -33,12 +32,10 @@ def __init__(self, db_session: Session) -> None: @cached_dto_result( cache_key=GIFT_COLLECTIONS_METADATA_KEY, response_model=GiftCollectionsMetadataDTO, - cache_ttl=60 * 60 * 24, # 1-day cache + cache_ttl=60 * 5, # 5-minute cache ) def get_metadata(self) -> GiftCollectionsMetadataDTO: - all_collections = self.collection_service.get_all( - slugs=core_settings.whitelisted_gift_collections - ) + all_collections = self.collection_service.get_all() collections_with_options = [] @@ -56,7 +53,6 @@ def get_metadata(self) -> GiftCollectionsMetadataDTO: patterns=options["patterns"], ) ) - return GiftCollectionsMetadataDTO(collections=collections_with_options) @staticmethod diff --git a/backend/core/src/core/constants.py b/backend/core/src/core/constants.py index 555f24bb..18a62628 100644 --- a/backend/core/src/core/constants.py +++ b/backend/core/src/core/constants.py @@ -43,7 +43,7 @@ CELERY_GATEWAY_INDEX_QUEUE_NAME = "gateway-index-queue" CELERY_INDEX_PRICES_QUEUE_NAME = "index-prices-queue" # Gifts -GIFT_COLLECTIONS_METADATA_KEY = "gifts-metadata-v2" +GIFT_COLLECTIONS_METADATA_KEY = "gifts-metadata-v3" CELERY_GIFT_FETCH_QUEUE_NAME = "gift-fetch-queue" UPDATED_GIFT_USER_IDS = "updated_gift_user_ids" diff --git a/backend/core/src/core/dtos/fields.py b/backend/core/src/core/dtos/fields.py new file mode 100644 index 00000000..7dad0597 --- /dev/null +++ b/backend/core/src/core/dtos/fields.py @@ -0,0 +1,7 @@ +from typing import Annotated + +from pydantic import PlainSerializer + +StringifiedInt = Annotated[ + int, PlainSerializer(lambda x: str(x), return_type=str, when_used="json") +] diff --git a/backend/core/src/core/dtos/gift/collection.py b/backend/core/src/core/dtos/gift/collection.py index eefe7377..574a8960 100644 --- a/backend/core/src/core/dtos/gift/collection.py +++ b/backend/core/src/core/dtos/gift/collection.py @@ -4,11 +4,12 @@ from pydantic import BaseModel from telethon.tl.types import StarGiftUnique +from core.dtos.fields import StringifiedInt from core.models.gift import GiftCollection class GiftCollectionDTO(BaseModel): - id: int + id: StringifiedInt title: str preview_url: str | None supply: int @@ -39,7 +40,7 @@ def from_telethon(cls, id: int, obj: StarGiftUnique, preview_url: str) -> Self: class GiftCollectionMetadataDTO(BaseModel): - id: int + id: StringifiedInt title: str preview_url: str | None supply: int @@ -54,7 +55,7 @@ class GiftCollectionsMetadataDTO(BaseModel): class GiftFilterDTO(BaseModel): - collection_id: int + collection_id: StringifiedInt model: str | None = None backdrop: str | None = None pattern: str | None = None diff --git a/backend/core/src/core/dtos/gift/item.py b/backend/core/src/core/dtos/gift/item.py index aeff7656..23ce8750 100644 --- a/backend/core/src/core/dtos/gift/item.py +++ b/backend/core/src/core/dtos/gift/item.py @@ -9,12 +9,13 @@ StarGiftAttributePattern, ) +from core.dtos.fields import StringifiedInt from core.models.gift import GiftUnique class GiftUniqueDTO(BaseModel): slug: str - collection_id: int + collection_id: StringifiedInt telegram_owner_id: int | None number: int blockchain_address: str | None diff --git a/backend/core/src/core/static/whitelisted_gift_collections.txt b/backend/core/src/core/static/whitelisted_gift_collections.txt index 9235fed1..d5223da9 100644 --- a/backend/core/src/core/static/whitelisted_gift_collections.txt +++ b/backend/core/src/core/static/whitelisted_gift_collections.txt @@ -1,23 +1,23 @@ -PlushPepe -DurovsCap -PreciousPeach -SwissWatch -BondedRing -GemSignet -ScaredCat -LootBag -NekoHelmet -IonGem -TopHat -MiniOscar -MagicPotion -AstralShard -VintageCigar -ElectricSkull -SignetRing -LowRider -WestsideSign -CupidCharm -HeartLocket -SnoopDogg -KhabibsPapakha +5936013938331222567 +5915521180483191380 +5933671725160989227 +5936043693864651359 +5870661333703197240 +5859442703032386168 +5837059369300132790 +5868659926187901653 +5933793770951673155 +5843762284240831056 +5897593557492957738 +5879737836550226478 +5846226946928673709 +5933629604416717361 +5857140566201991735 +5846192273657692751 +5936085638515261992 +6014675319464657779 +6014697240977737490 +5868561433997870501 +5868455043362980631 +6014591077976114307 +5839094187366024301 diff --git a/frontend/src/pages/admin/ConditionPage/components/Gifts/Gifts.tsx b/frontend/src/pages/admin/ConditionPage/components/Gifts/Gifts.tsx index 2cd79183..df70af0a 100644 --- a/frontend/src/pages/admin/ConditionPage/components/Gifts/Gifts.tsx +++ b/frontend/src/pages/admin/ConditionPage/components/Gifts/Gifts.tsx @@ -1,14 +1,14 @@ -import { AppSelect, Image, ListInput, ListItem, Text } from '@components' -import { List } from '@components' -import { Block } from '@components' -import { useEffect, useState } from 'react' +import { AppSelect, Image, ListInput, ListItem, Text } from '@components'; +import { List } from '@components'; +import { Block } from '@components'; +import { useEffect } from 'react'; -import { Condition, GiftsCollection } from '@store' -import { useCondition } from '@store' -import { useConditionActions } from '@store' +import { Condition, GiftsCollection } from '@store'; +import { useCondition } from '@store'; +import { useConditionActions } from '@store'; -import { ConditionComponentProps } from '../types' -import { Skeleton } from './Skeleton' +import { ConditionComponentProps } from '../types'; +import { Skeleton } from './Skeleton'; export const Gifts = ({ isNewCondition, @@ -21,9 +21,6 @@ export const Gifts = ({ useConditionActions() const { giftsData } = useCondition() - const [currentCollection, setCurrentCollection] = - useState(null) - const fetchGifts = async () => { try { await fetchGiftsAction() @@ -39,31 +36,23 @@ export const Gifts = ({ useEffect(() => { if (giftsData?.length) { + const selectedCollectionId: string = + condition?.collectionId != null + ? String(condition.collectionId) + : (condition?.collection as GiftsCollection)?.id != null + ? String((condition?.collection as GiftsCollection).id) + : giftsData[0].id + const updatedConditionState: Partial = { type: 'gift_collection', category: null, - isEnabled: !!condition?.isEnabled || true, - collectionSlug: - condition?.collectionSlug || - condition?.slug || - (condition?.collection as GiftsCollection)?.slug || - giftsData[0].slug, - model: condition?.model || null, - backdrop: condition?.backdrop || null, - pattern: condition?.pattern || null, - expected: condition?.expected || '', + isEnabled: condition?.isEnabled ?? true, + collectionId: selectedCollectionId, + model: condition?.model ?? null, + backdrop: condition?.backdrop ?? null, + pattern: condition?.pattern ?? null, + expected: condition?.expected ?? '', } - - setCurrentCollection( - giftsData.find( - (collection) => - collection.slug === - (condition?.collectionSlug || - condition?.slug || - (condition?.collection as GiftsCollection)?.slug) - ) || giftsData[0] - ) - setInitialState(updatedConditionState as Partial) } }, [giftsData?.length, condition, isNewCondition]) @@ -72,6 +61,12 @@ export const Gifts = ({ return } + // derive currentCollection from the authoritative conditionState.collectionId + const currentCollection: GiftsCollection = + giftsData.find((collection) => + collection.id === String(conditionState?.collectionId ?? giftsData[0].id) + ) || giftsData[0] + return ( <> @@ -81,18 +76,22 @@ export const Gifts = ({ after={ { - setCurrentCollection( - giftsData.find((collection) => collection.slug === value) || - giftsData[0] - ) + const selectedIdStr = String(value) + + // reset dependent fields handleChangeCondition('model', null) handleChangeCondition('backdrop', null) handleChangeCondition('pattern', null) - handleChangeCondition('collectionSlug', value) + + // store selected collection id in condition state + handleChangeCondition('collectionId', selectedIdStr) }} - value={conditionState?.collectionSlug} + // the select value should reflect the selected collection id (string) + value={String( + conditionState?.collectionId ?? currentCollection?.id ?? giftsData[0].id + )} options={giftsData.map((collection) => ({ - value: collection.slug, + value: collection.id, name: collection.title, }))} /> diff --git a/frontend/src/store/condition/types.ts b/frontend/src/store/condition/types.ts index 7b55cdc1..61ad55e5 100644 --- a/frontend/src/store/condition/types.ts +++ b/frontend/src/store/condition/types.ts @@ -102,12 +102,12 @@ export interface StickersCollection { } export interface GiftsCollection { + id: string, title: string backdrops: string[] models: string[] patterns: string[] previewUrl: string - slug: string supply: number upgradedCount: number }