mirror of
https://github.com/civitai/civitai.git
synced 2026-09-20 22:08:18 +08:00
live auction views, live updating bids
This commit is contained in:
Generated
+52
@@ -45,6 +45,7 @@
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@next/bundle-analyzer": "^15.0.3",
|
||||
"@next/third-parties": "^15.0.3",
|
||||
"@number-flow/react": "^0.5.7",
|
||||
"@okikio/sharedworker": "^1.0.4",
|
||||
"@paddle/paddle-js": "^1.2.1",
|
||||
"@paddle/paddle-node-sdk": "^1.4.1",
|
||||
@@ -3158,6 +3159,20 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@number-flow/react": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@number-flow/react/-/react-0.5.7.tgz",
|
||||
"integrity": "sha512-Fm1ZTUx5SYFZcJ3NjNKzC513Sq0XbU//X1yIEJ33MLBNyff+S16akGvez1zD1EjBHbgRGUyyNKQP6U8u0cszvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esm-env": "^1.1.4",
|
||||
"number-flow": "0.5.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@okikio/sharedworker": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@okikio/sharedworker/-/sharedworker-1.0.4.tgz",
|
||||
@@ -10101,6 +10116,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/esm-env": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
|
||||
@@ -15714,6 +15735,15 @@
|
||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/number-flow": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/number-flow/-/number-flow-0.5.5.tgz",
|
||||
"integrity": "sha512-oE+gyA3S0ar8un2dg80TlEi3hjvi/UnTewHl2bu9dGKMxU7nT8VTUdIf1X7NbRLslqyyTyxdSmIAv/QJhaq1pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esm-env": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/oauth": {
|
||||
"version": "0.9.15",
|
||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
|
||||
@@ -23564,6 +23594,15 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@number-flow/react": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@number-flow/react/-/react-0.5.7.tgz",
|
||||
"integrity": "sha512-Fm1ZTUx5SYFZcJ3NjNKzC513Sq0XbU//X1yIEJ33MLBNyff+S16akGvez1zD1EjBHbgRGUyyNKQP6U8u0cszvA==",
|
||||
"requires": {
|
||||
"esm-env": "^1.1.4",
|
||||
"number-flow": "0.5.5"
|
||||
}
|
||||
},
|
||||
"@okikio/sharedworker": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@okikio/sharedworker/-/sharedworker-1.0.4.tgz",
|
||||
@@ -28645,6 +28684,11 @@
|
||||
"integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"esm-env": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="
|
||||
},
|
||||
"espree": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
|
||||
@@ -32307,6 +32351,14 @@
|
||||
"boolbase": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"number-flow": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/number-flow/-/number-flow-0.5.5.tgz",
|
||||
"integrity": "sha512-oE+gyA3S0ar8un2dg80TlEi3hjvi/UnTewHl2bu9dGKMxU7nT8VTUdIf1X7NbRLslqyyTyxdSmIAv/QJhaq1pw==",
|
||||
"requires": {
|
||||
"esm-env": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"oauth": {
|
||||
"version": "0.9.15",
|
||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@next/bundle-analyzer": "^15.0.3",
|
||||
"@next/third-parties": "^15.0.3",
|
||||
"@number-flow/react": "^0.5.7",
|
||||
"@okikio/sharedworker": "^1.0.4",
|
||||
"@paddle/paddle-js": "^1.2.1",
|
||||
"@paddle/paddle-node-sdk": "^1.4.1",
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
IconCalendar,
|
||||
IconLayoutSidebarLeftExpand,
|
||||
IconMoodSmile,
|
||||
IconPlugConnected,
|
||||
} from '@tabler/icons-react';
|
||||
import { clsx } from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -30,7 +31,7 @@ import { AlertWithIcon } from '~/components/AlertWithIcon/AlertWithIcon';
|
||||
import { getModelTypesForAuction } from '~/components/Auction/auction.utils';
|
||||
import { ModelPlacementCard } from '~/components/Auction/AuctionPlacementCard';
|
||||
import { useAuctionContext } from '~/components/Auction/AuctionProvider';
|
||||
import { usePurchaseBid } from '~/components/Auction/AuctionUtils';
|
||||
import { AuctionViews, usePurchaseBid } from '~/components/Auction/AuctionUtils';
|
||||
import { BuzzTransactionButton } from '~/components/Buzz/BuzzTransactionButton';
|
||||
import { CosmeticCard } from '~/components/CardTemplates/CosmeticCard';
|
||||
import { Countdown } from '~/components/Countdown/Countdown';
|
||||
@@ -38,6 +39,7 @@ import { CurrencyIcon } from '~/components/Currency/CurrencyIcon';
|
||||
import { HelpButton } from '~/components/HelpButton/HelpButton';
|
||||
import { ResourceSelect } from '~/components/ImageGeneration/GenerationForm/ResourceSelect';
|
||||
import { featureInfo } from '~/components/Model/ModelVersions/ModelVersionPopularity';
|
||||
import { useSignalContext } from '~/components/Signals/SignalsProvider';
|
||||
import { useTourContext } from '~/components/Tours/ToursProvider';
|
||||
import { useIsMobile } from '~/hooks/useIsMobile';
|
||||
import { NumberInputWrapper } from '~/libs/form/components/NumberInputWrapper';
|
||||
@@ -79,11 +81,17 @@ export const AuctionTopSection = ({ refreshFunc }: { refreshFunc?: () => any })
|
||||
const features = useFeatureFlags();
|
||||
const { runTour } = useTourContext();
|
||||
const { drawerToggle } = useAuctionContext();
|
||||
const { connected } = useSignalContext();
|
||||
|
||||
// {/*<Group className="sticky top-0 right-0">*/}
|
||||
|
||||
return (
|
||||
<Group position="right">
|
||||
{!connected && (
|
||||
<Tooltip label="Not connected. May not receive live updates.">
|
||||
<IconPlugConnected color="orangered" />
|
||||
</Tooltip>
|
||||
)}
|
||||
{features.appTour && (
|
||||
<HelpButton
|
||||
data-tour="auction:reset"
|
||||
@@ -127,6 +135,7 @@ export const AuctionTopSection = ({ refreshFunc }: { refreshFunc?: () => any })
|
||||
</Stack>
|
||||
</HoverCard.Dropdown>
|
||||
</HoverCard>
|
||||
<AuctionViews />
|
||||
<Button
|
||||
className="md:hidden"
|
||||
onClick={drawerToggle}
|
||||
@@ -138,7 +147,11 @@ export const AuctionTopSection = ({ refreshFunc }: { refreshFunc?: () => any })
|
||||
<Text>Auctions</Text>
|
||||
</Group>
|
||||
</Button>
|
||||
{!!refreshFunc && <Button onClick={() => refreshFunc()}>Refresh</Button>}
|
||||
{!!refreshFunc && (
|
||||
<Button variant="light" onClick={() => refreshFunc()}>
|
||||
Refresh
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
@@ -320,6 +333,7 @@ export const AuctionInfo = () => {
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
justifyItems: 'center',
|
||||
display: 'grid', // for firefox
|
||||
}}
|
||||
buttonProps={{
|
||||
fullWidth: mobile,
|
||||
|
||||
@@ -312,6 +312,7 @@ const SectionBidInfo = ({
|
||||
sx={{
|
||||
fontSize: '1.25rem',
|
||||
}}
|
||||
asCounter={true}
|
||||
/>
|
||||
</Tooltip>
|
||||
{right}
|
||||
|
||||
@@ -16,16 +16,19 @@ type AuctionState = {
|
||||
selectedModel: GenerationResource | undefined;
|
||||
validAuction: boolean;
|
||||
justBid: { auctionId: number; entityId: number } | undefined;
|
||||
viewing: { [p: number]: number };
|
||||
};
|
||||
type AuctionContextState = {
|
||||
selectedAuction: AuctionState['selectedAuction'];
|
||||
selectedModel: AuctionState['selectedModel'];
|
||||
validAuction: AuctionState['validAuction'];
|
||||
justBid: AuctionState['justBid'];
|
||||
viewing: AuctionState['viewing'];
|
||||
setSelectedAuction: Dispatch<SetStateAction<AuctionState['selectedAuction']>>;
|
||||
setSelectedModel: Dispatch<SetStateAction<AuctionState['selectedModel']>>;
|
||||
setValidAuction: Dispatch<SetStateAction<AuctionState['validAuction']>>;
|
||||
setJustBid: Dispatch<SetStateAction<AuctionState['justBid']>>;
|
||||
setViewing: Dispatch<SetStateAction<AuctionState['viewing']>>;
|
||||
drawerIsOpen: boolean;
|
||||
drawerToggle: () => void;
|
||||
drawerClose: () => void;
|
||||
@@ -48,6 +51,7 @@ export const AuctionContextProvider = ({ children }: { children: ReactNode }) =>
|
||||
const [selectedModel, setSelectedModel] = useState<AuctionState['selectedModel']>(undefined);
|
||||
const [validAuction, setValidAuction] = useState<AuctionState['validAuction']>(true);
|
||||
const [justBid, setJustBid] = useState<AuctionState['justBid']>(undefined);
|
||||
const [viewing, setViewing] = useState<AuctionState['viewing']>({});
|
||||
const [drawerIsOpen, { close: drawerClose, toggle: drawerToggle }] = useDisclosure();
|
||||
const router = useRouter();
|
||||
|
||||
@@ -76,10 +80,12 @@ export const AuctionContextProvider = ({ children }: { children: ReactNode }) =>
|
||||
selectedModel,
|
||||
validAuction,
|
||||
justBid,
|
||||
viewing,
|
||||
setSelectedAuction,
|
||||
setSelectedModel,
|
||||
setValidAuction,
|
||||
setJustBid,
|
||||
setViewing,
|
||||
drawerIsOpen,
|
||||
drawerToggle,
|
||||
drawerClose,
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import { ActionIcon, ActionIconProps, Stack, Text, Tooltip } from '@mantine/core';
|
||||
import { ActionIcon, ActionIconProps, Group, Paper, Stack, Text, Tooltip } from '@mantine/core';
|
||||
import { showNotification, updateNotification } from '@mantine/notifications';
|
||||
import { IconCheck, IconGavel, IconX } from '@tabler/icons-react';
|
||||
import NumberFlow from '@number-flow/react';
|
||||
import { IconCheck, IconGavel, IconUsers, IconX } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useAuctionContext } from '~/components/Auction/AuctionProvider';
|
||||
import { useBuzzTransaction } from '~/components/Buzz/buzz.utils';
|
||||
import { CurrencyBadge } from '~/components/Currency/CurrencyBadge';
|
||||
import { useSignalConnection, useSignalTopic } from '~/components/Signals/SignalsProvider';
|
||||
import { useCurrentUser } from '~/hooks/useCurrentUser';
|
||||
import {
|
||||
useSignalConnection,
|
||||
useSignalContext,
|
||||
useSignalTopic,
|
||||
} from '~/components/Signals/SignalsProvider';
|
||||
import { useFeatureFlags } from '~/providers/FeatureFlagsProvider';
|
||||
import { SignalMessages, SignalTopic } from '~/server/common/enums';
|
||||
import type { GetAuctionBySlugReturn } from '~/server/services/auction.service';
|
||||
@@ -21,6 +25,7 @@ export function usePurchaseBid() {
|
||||
const queryUtils = trpc.useUtils();
|
||||
const [createLoading, setCreateLoading] = useState(false);
|
||||
const { setJustBid } = useAuctionContext();
|
||||
const { connected } = useSignalContext();
|
||||
|
||||
const { conditionalPerformTransaction } = useBuzzTransaction({
|
||||
message: (requiredBalance: number) =>
|
||||
@@ -68,7 +73,9 @@ export function usePurchaseBid() {
|
||||
});
|
||||
|
||||
// TODO updates instead for MyBids
|
||||
await queryUtils.auction.getBySlug.invalidate({ slug: res.slug });
|
||||
if (!connected) {
|
||||
await queryUtils.auction.getBySlug.invalidate({ slug: res.slug });
|
||||
}
|
||||
await queryUtils.auction.getMyBids.invalidate();
|
||||
await queryUtils.auction.getMyRecurringBids.invalidate();
|
||||
await queryUtils.model.getRecentlyBid.invalidate();
|
||||
@@ -204,20 +211,59 @@ export const BidModelButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuctionTopicListener = (auctionId?: number) => {
|
||||
const utils = trpc.useUtils();
|
||||
const currentUser = useCurrentUser();
|
||||
export const AuctionViews = () => {
|
||||
const { viewing, selectedAuction } = useAuctionContext();
|
||||
|
||||
// TODO
|
||||
useSignalConnection(SignalMessages.AuctionUpdate, (data: any) => {
|
||||
// console.log('auction update', data);
|
||||
});
|
||||
useSignalConnection(SignalMessages.AuctionBidChange, (data: any) => {
|
||||
const views = selectedAuction?.id ? viewing[selectedAuction.id] ?? 0 : 0;
|
||||
if (!views) return <></>;
|
||||
|
||||
return (
|
||||
<Tooltip label="Currently viewing">
|
||||
<Paper radius="sm" shadow="xs" px={8} py={4} withBorder className="bg-gray-0 dark:bg-dark-6">
|
||||
<Group spacing={4} className="min-w-[55px] cursor-default justify-center">
|
||||
<IconUsers size={14} />
|
||||
<NumberFlow
|
||||
format={{ notation: 'compact' }}
|
||||
respectMotionPreference={false}
|
||||
value={views}
|
||||
className="text-sm"
|
||||
/>
|
||||
{/*<button*/}
|
||||
{/* onClick={() => {*/}
|
||||
{/* const delta = Math.floor(Math.random() * 100000);*/}
|
||||
{/* if (selectedAuction)*/}
|
||||
{/* setViewing((prev) => ({ ...prev, [selectedAuction?.id]: delta }));*/}
|
||||
{/* }}*/}
|
||||
{/*>*/}
|
||||
{/* change*/}
|
||||
{/*</button>*/}
|
||||
</Group>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuctionTopicListener = (auctionId?: number) => {
|
||||
const queryUtils = trpc.useUtils();
|
||||
const { setViewing } = useAuctionContext();
|
||||
|
||||
// console.log('listening to auction', auctionId);
|
||||
|
||||
useSignalConnection(SignalMessages.AuctionBidChange, (data: GetAuctionBySlugReturn) => {
|
||||
// console.log('auction bid change', data);
|
||||
queryUtils.auction.getBySlug.setData({ slug: data.auctionBase.slug }, data);
|
||||
});
|
||||
useSignalConnection(SignalMessages.TopicUpdate, (data: { topic: string; count: number }) => {
|
||||
// if topic === .... then get count
|
||||
// console.log('auction count', data);
|
||||
setViewing((prev) => {
|
||||
const auctionId = parseInt(data.topic.split(':')[1]);
|
||||
if (isNaN(auctionId)) return prev;
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[auctionId]: Math.max(0, data.count),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// TODO is there a race condition? missing the first topic message
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { Badge, BadgeProps, Loader, MantineSize, Tooltip, useMantineTheme } from '@mantine/core';
|
||||
import { Currency } from '~/shared/utils/prisma/enums';
|
||||
import {
|
||||
Badge,
|
||||
BadgeProps,
|
||||
Loader,
|
||||
MantineSize,
|
||||
Text,
|
||||
Tooltip,
|
||||
useMantineTheme,
|
||||
} from '@mantine/core';
|
||||
import NumberFlow from '@number-flow/react';
|
||||
import { IconProps } from '@tabler/icons-react';
|
||||
import React, { forwardRef } from 'react';
|
||||
import { BuzzTypeDistribution } from '~/components/Buzz/buzz.utils';
|
||||
import { CurrencyConfig } from '~/server/common/constants';
|
||||
import { Currency } from '~/shared/utils/prisma/enums';
|
||||
import { formatCurrencyForDisplay } from '~/utils/number-helpers';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
type Props = BadgeProps & {
|
||||
currency: Currency;
|
||||
@@ -16,6 +25,7 @@ type Props = BadgeProps & {
|
||||
textColor?: string;
|
||||
type?: string;
|
||||
typeDistrib?: BuzzTypeDistribution;
|
||||
asCounter?: boolean;
|
||||
};
|
||||
|
||||
const iconSize: Record<MantineSize, number> = {
|
||||
@@ -40,6 +50,7 @@ export const CurrencyBadge = forwardRef<HTMLDivElement, Props>(
|
||||
textColor,
|
||||
type,
|
||||
typeDistrib,
|
||||
asCounter,
|
||||
...badgeProps
|
||||
},
|
||||
ref
|
||||
@@ -109,9 +120,15 @@ export const CurrencyBadge = forwardRef<HTMLDivElement, Props>(
|
||||
<Loader size="xs" variant="dots" color={colorString} />
|
||||
) : (
|
||||
<div className="flex items-center gap-1">
|
||||
{formatter
|
||||
? formatter(unitAmount)
|
||||
: `${value || 0} ${displayCurrency ? currency : ''}`}
|
||||
{asCounter ? (
|
||||
<NumberFlow respectMotionPreference={false} value={unitAmount} />
|
||||
) : (
|
||||
<Text>
|
||||
{formatter
|
||||
? formatter(unitAmount)
|
||||
: `${value || 0} ${displayCurrency ? currency : ''}`}
|
||||
</Text>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -133,11 +133,8 @@ export enum SignalMessages {
|
||||
NotificationNew = 'notification:new',
|
||||
ModelVersionPopularityUpdate = 'model-version:popularity:update',
|
||||
Pong = 'pong',
|
||||
// Creator Program:
|
||||
CompensationPoolUpdate = 'creators-program:compensation-pool-update',
|
||||
CashInvalidator = 'creators-program:cash-invalidator',
|
||||
// Auction
|
||||
AuctionUpdate = 'auction:update',
|
||||
AuctionBidChange = 'auction:bid-change',
|
||||
TopicUpdate = 'topic:connections',
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ export const handleAuctions = createJob(jobName, '1 0 * * *', async () => {
|
||||
log('-----------');
|
||||
}
|
||||
|
||||
// TODO possibly send signals
|
||||
|
||||
log('end', dayjs().toDate());
|
||||
|
||||
await dbKV.set(kvKey, 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { uniq } from 'lodash-es';
|
||||
import { getModelTypesForAuction } from '~/components/Auction/auction.utils';
|
||||
import { NotificationCategory } from '~/server/common/enums';
|
||||
import { NotificationCategory, SignalMessages, SignalTopic } from '~/server/common/enums';
|
||||
import { dbRead, dbWrite } from '~/server/db/client';
|
||||
import { logToAxiom } from '~/server/logging/client';
|
||||
import type { DetailsCanceledBid } from '~/server/notifications/auction.notifications';
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
import { AuctionType, Availability, BuzzAccountType } from '~/shared/utils/prisma/enums';
|
||||
import { formatDate } from '~/utils/date-helpers';
|
||||
import { withRetries } from '~/utils/errorHandling';
|
||||
import { signalClient } from '~/utils/signal-client';
|
||||
|
||||
export const auctionBaseSelect = Prisma.validator<Prisma.AuctionBaseSelect>()({
|
||||
id: true,
|
||||
@@ -496,6 +497,16 @@ export const createBid = async ({
|
||||
});
|
||||
}
|
||||
|
||||
// TODO there is probably a better way to do this that avoids refetching everything, but we need to update all positions and numbers
|
||||
const signalData = await getAuctionBySlug({ slug: auctionData.auctionBase.slug });
|
||||
signalClient
|
||||
.topicSend({
|
||||
topic: `${SignalTopic.Auction}:${auctionId}`,
|
||||
target: SignalMessages.AuctionBidChange,
|
||||
data: signalData,
|
||||
})
|
||||
.catch();
|
||||
|
||||
// TODO fetch the entity that was knocked out (if any)
|
||||
// get all the bids userIds
|
||||
|
||||
@@ -525,8 +536,12 @@ export const deleteBid = async ({ userId, bidId }: DeleteBidInput & { userId: nu
|
||||
transactionIds: true,
|
||||
auction: {
|
||||
select: {
|
||||
id: true,
|
||||
startAt: true,
|
||||
endAt: true,
|
||||
auctionBase: {
|
||||
select: { slug: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -546,6 +561,15 @@ export const deleteBid = async ({ userId, bidId }: DeleteBidInput & { userId: nu
|
||||
deleted: true,
|
||||
},
|
||||
});
|
||||
|
||||
const signalData = await getAuctionBySlug({ slug: bid.auction.auctionBase.slug });
|
||||
signalClient
|
||||
.topicSend({
|
||||
topic: `${SignalTopic.Auction}:${bid.auction.id}`,
|
||||
target: SignalMessages.AuctionBidChange,
|
||||
data: signalData,
|
||||
})
|
||||
.catch();
|
||||
};
|
||||
|
||||
export const deleteBidsForModel = async ({ modelId }: { modelId: number }) => {
|
||||
@@ -560,12 +584,18 @@ export const deleteBidsForModel = async ({ modelId }: { modelId: number }) => {
|
||||
const versionIds = model.modelVersions.map((mv) => mv.id);
|
||||
if (!versionIds.length) throw throwBadRequestError('Model has no versions.');
|
||||
|
||||
const aIds = (
|
||||
await dbWrite.auction.findMany({
|
||||
where: { startAt: { lte: now }, endAt: { gt: now } },
|
||||
select: { id: true },
|
||||
})
|
||||
).map((a) => a.id);
|
||||
const aData = await dbWrite.auction.findMany({
|
||||
where: { startAt: { lte: now }, endAt: { gt: now } },
|
||||
select: {
|
||||
id: true,
|
||||
auctionBase: {
|
||||
select: {
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const aIds = aData.map((a) => a.id);
|
||||
|
||||
let deletedIds: number[] = [];
|
||||
let deletedRecurringIds: number[] = [];
|
||||
@@ -647,7 +677,16 @@ export const deleteBidsForModel = async ({ modelId }: { modelId: number }) => {
|
||||
deletedRecurringIds = recToDelete.map((d) => d.id);
|
||||
}
|
||||
|
||||
// TODO send signal
|
||||
for (const a of aData) {
|
||||
const signalData = await getAuctionBySlug({ slug: a.auctionBase.slug });
|
||||
signalClient
|
||||
.topicSend({
|
||||
topic: `${SignalTopic.Auction}:${a.id}`,
|
||||
target: SignalMessages.AuctionBidChange,
|
||||
data: signalData,
|
||||
})
|
||||
.catch();
|
||||
}
|
||||
|
||||
return {
|
||||
bidsDeleted: deletedIds,
|
||||
|
||||
@@ -111,7 +111,7 @@ const featureFlags = createFeatureFlags({
|
||||
generationOnlyModels: ['mod', 'granted', 'gold'],
|
||||
appTour: ['public'],
|
||||
privateModels: ['mod', 'granted'],
|
||||
auctions: ['mod'],
|
||||
auctions: ['public'],
|
||||
});
|
||||
|
||||
export const featureFlagKeys = Object.keys(featureFlags) as FeatureFlagKey[];
|
||||
|
||||
@@ -39,7 +39,7 @@ class SignalClient {
|
||||
target,
|
||||
data,
|
||||
}: {
|
||||
topic: SignalTopic;
|
||||
topic: `${SignalTopic}${'' | `:${number}`}`;
|
||||
target: string;
|
||||
data: Record<string, unknown>;
|
||||
}) => {
|
||||
|
||||
Reference in New Issue
Block a user