Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions backend/core/src/core/actions/gift.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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 = []

Expand All @@ -56,7 +53,6 @@ def get_metadata(self) -> GiftCollectionsMetadataDTO:
patterns=options["patterns"],
)
)

return GiftCollectionsMetadataDTO(collections=collections_with_options)

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion backend/core/src/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
7 changes: 7 additions & 0 deletions backend/core/src/core/dtos/fields.py
Original file line number Diff line number Diff line change
@@ -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")
]
7 changes: 4 additions & 3 deletions backend/core/src/core/dtos/gift/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion backend/core/src/core/dtos/gift/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 23 additions & 23 deletions backend/core/src/core/static/whitelisted_gift_collections.txt
Original file line number Diff line number Diff line change
@@ -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
79 changes: 39 additions & 40 deletions frontend/src/pages/admin/ConditionPage/components/Gifts/Gifts.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -21,9 +21,6 @@ export const Gifts = ({
useConditionActions()
const { giftsData } = useCondition()

const [currentCollection, setCurrentCollection] =
useState<GiftsCollection | null>(null)

const fetchGifts = async () => {
try {
await fetchGiftsAction()
Expand All @@ -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<Condition> = {
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<Condition>)
}
}, [giftsData?.length, condition, isNewCondition])
Expand All @@ -72,6 +61,12 @@ export const Gifts = ({
return <Skeleton />
}

// derive currentCollection from the authoritative conditionState.collectionId
const currentCollection: GiftsCollection =
giftsData.find((collection) =>
collection.id === String(conditionState?.collectionId ?? giftsData[0].id)
) || giftsData[0]

return (
<>
<Block margin="top" marginValue={24} fadeIn>
Expand All @@ -81,18 +76,22 @@ export const Gifts = ({
after={
<AppSelect
onChange={(value) => {
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,
}))}
/>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/store/condition/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Loading