Compare commits

..

1 Commits

Author SHA1 Message Date
672677396f [backend]: add settings page 2025-08-13 06:46:56 +03:00
47 changed files with 15 additions and 2296 deletions

View File

@ -112,24 +112,7 @@ export default [
"@typescript-eslint/no-misused-promises": ["error", { "@typescript-eslint/no-misused-promises": ["error", {
"checksVoidReturn": false "checksVoidReturn": false
} }
], ]
'@typescript-eslint/naming-convention': ['error',
{
selector: 'enum',
format: ['UPPER_CASE', 'PascalCase'],
},
{
selector: 'variable',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
},
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
},
{
selector: 'typeLike',
format: ['PascalCase'],
}],
}, },
}, },
{ {

View File

@ -30,7 +30,6 @@
"@radix-ui/react-switch": "1.2.5", "@radix-ui/react-switch": "1.2.5",
"@radix-ui/react-tabs": "^1.1.12", "@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-tooltip": "1.2.7", "@radix-ui/react-tooltip": "1.2.7",
"@tanstack/react-table": "8.21.3",
"apollo-upload-client": "18.0.1", "apollo-upload-client": "18.0.1",
"class-variance-authority": "0.7.1", "class-variance-authority": "0.7.1",
"clsx": "2.1.1", "clsx": "2.1.1",
@ -56,7 +55,6 @@
"@next/eslint-plugin-next": "15.4.5", "@next/eslint-plugin-next": "15.4.5",
"@parcel/watcher": "^2.5.1", "@parcel/watcher": "^2.5.1",
"@tailwindcss/postcss": "4.1.11", "@tailwindcss/postcss": "4.1.11",
"@types/apollo-upload-client": "18.0.0",
"@types/node": "22.17.0", "@types/node": "22.17.0",
"@types/react": "19.1.9", "@types/react": "19.1.9",
"@types/react-dom": "19.1.7", "@types/react-dom": "19.1.7",

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { ChangeChatSettings } from '@/components/features/chat/settings/ChangeChatSettings';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.chat.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const ChatSettingsPage = () => <ChangeChatSettings />;
export default ChatSettingsPage;

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { FollowersTable } from '@/components/features/follow/table/FollowersTable';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.followers.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const FollowersPage = () => <FollowersTable />;
export default FollowersPage;

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { KeysSettings } from '@/components/features/keys/settings/KeysSettings';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.keys.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const KeysSettingsPage = () => <KeysSettings />;
export default KeysSettingsPage;

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { PlansTable } from '@/components/features/sponsorship/plan/table/PlansTable';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.plans.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const PlansPage = () => <PlansTable />;
export default PlansPage;

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { SponsorsTable } from '@/components/features/sponsorship/subscription/table/SponsorsTable';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.sponsors.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const SponsorsPage = () => <SponsorsTable />;
export default SponsorsPage;

View File

@ -1,20 +0,0 @@
import { getTranslations } from 'next-intl/server';
import { TransactionsTable } from '@/components/features/sponsorship/transactions/table/TransactionsTable';
import { NO_INDEX_PAGE } from '@/libs/constants/seo.constants';
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('dashboard.transactions.header');
return {
title: t('heading'),
description: t('description'),
...NO_INDEX_PAGE,
};
}
const TransactionsPage = () => <TransactionsTable />;
export default TransactionsPage;

View File

@ -14,5 +14,6 @@ export async function generateMetadata(): Promise<Metadata> {
}; };
} }
const DeactivatePage = () => <DeactivateForm />; export default function DeactivatePage() {
export default DeactivatePage; return <DeactivateForm />;
}

View File

@ -63,7 +63,7 @@ export const DeactivateForm = () => {
const { isValid } = form.formState; const { isValid } = form.formState;
function onSubmit(data: TypeDeactivateSchema) { function onSubmit(data: TypeDeactivateSchema) {
void deactivate({ variables: { data } }); deactivate({ variables: { data } });
} }
return ( return (

View File

@ -1,132 +0,0 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTranslations } from 'next-intl';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { Form, FormField } from '@/components/ui/common/Form';
import { Heading } from '@/components/ui/elements/Heading';
import {
ToggleCard,
ToggleCardSkeleton,
} from '@/components/ui/elements/ToggleCard';
import { useChangeChatSettingsMutation } from '@/graphql/generated/output';
import { useCurrent } from '@/hooks/useCurrent';
import { changeChatSettingsSchema } from '@/schemas/chat/change-chat.settings.schema';
import type { TypeChangeChatSettingsSchema } from '@/schemas/chat/change-chat.settings.schema';
export const ChangeChatSettings = () => {
const t = useTranslations('dashboard.chat');
const { user, isLoadingProfile } = useCurrent();
const form = useForm<TypeChangeChatSettingsSchema>({
resolver: zodResolver(changeChatSettingsSchema),
values: {
isChatEnable: user?.stream.isChatEnable ?? false,
isChatFollowersOnly: user?.stream.isChatFollowersOnly ?? false,
isChatPremiumFollowersOnly:
user?.stream.isChatPremiumFollowersOnly ?? false,
},
});
const [update, { loading: isLoadingUpdate }] = useChangeChatSettingsMutation({
onCompleted(data) {
toast.success(t('successMessage'));
},
onError() {
toast.error(t('errorMessage'));
},
});
function onChange(
field: keyof TypeChangeChatSettingsSchema,
value: boolean,
) {
form.setValue(field, value);
void update({
variables: {
data: { ...form.getValues(), [field]: value },
},
});
}
return (
<div className="lg:px-10">
<Heading
description={t('header.description')}
size="lg"
title={t('header.heading')}
/>
<div className="mt-3 space-y-6">
{isLoadingProfile
? Array.from({ length: 3 }).map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<ToggleCardSkeleton key={index} />
))
: (
<Form {...form}>
<FormField
control={form.control}
name="isChatEnable"
render={({ field }) => (
<ToggleCard
description={t('isChatEnabled.description')}
heading={t('isChatEnabled.heading')}
isDisabled={isLoadingUpdate}
value={field.value}
onChange={(value) => { onChange('isChatEnable', value); }}
/>
)}
/>
<FormField
control={form.control}
name="isChatFollowersOnly"
render={({ field }) => (
<ToggleCard
description={t(
'isChatFollowersOnly.description',
)}
heading={t('isChatFollowersOnly.heading')}
isDisabled={isLoadingUpdate}
value={field.value}
onChange={(value) => { onChange('isChatFollowersOnly', value); }}
/>
)}
/>
<FormField
control={form.control}
name="isChatPremiumFollowersOnly"
render={({ field }) => (
<ToggleCard
description={t(
'isChatPremiumFollowersOnly.description',
)}
heading={t(
'isChatPremiumFollowersOnly.heading',
)}
isDisabled={
isLoadingUpdate || !user?.isVerified
}
value={field.value}
onChange={(value) => {
onChange(
'isChatPremiumFollowersOnly',
value,
);
}}
/>
)}
/>
</Form>
)}
</div>
</div>
);
};

View File

@ -1,106 +0,0 @@
'use client';
import { MoreHorizontal, User } from 'lucide-react';
import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/common/Button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/common/DropdownMenu';
import { ChannelAvatar } from '@/components/ui/elements/ChannelAvatar';
import { ChannelVerified } from '@/components/ui/elements/ChannelVerified';
import { DataTable, DataTableSkeleton } from '@/components/ui/elements/DataTable';
import { Heading } from '@/components/ui/elements/Heading';
import {
type FindMyFollowersQuery,
useFindMyFollowersQuery,
} from '@/graphql/generated/output';
import { formatDate } from '@/utils/format-date';
import type { ColumnDef } from '@tanstack/react-table';
const FollowerCell = ({ row }: any) => (
<div className="flex items-center gap-x-2">
<ChannelAvatar channel={row.original.follower} size="sm" />
<h2>
{row.original.follower.name}
</h2>
{row.original.follower.isVerified ? <ChannelVerified size="sm" /> : null}
</div>
);
const FollowerActionCell = ({ row }: any) => {
const t = useTranslations('dashboard.followers');
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="size-8 p-0" variant="ghost">
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right">
<Link
href={`/${row.original.follower.name}`}
target="_blank"
>
<DropdownMenuItem>
<User className="mr-2 size-4" />
{t('columns.viewChannel')}
</DropdownMenuItem>
</Link>
</DropdownMenuContent>
</DropdownMenu>
);
};
export const FollowersTable = () => {
const t = useTranslations('dashboard.followers');
const { data, loading: isLoadingFollowers } = useFindMyFollowersQuery();
const followers = data?.findMyFollowers ?? [];
const followersColumns: ColumnDef<FindMyFollowersQuery['findMyFollowers'][0]>[] = [
{
accessorKey: 'createdAt',
header: t('columns.date'),
cell: ({ row }) => formatDate(row.original.createdAt),
},
{
accessorKey: 'follower',
header: t('columns.user'),
cell: FollowerCell,
},
{
accessorKey: 'actions',
header: t('columns.actions'),
cell: FollowerActionCell,
},
];
return (
<div className="lg:px-10">
<Heading
description={t('header.description')}
size="lg"
title={t('header.heading')}
/>
<div className="mt-5">
{
isLoadingFollowers
? <DataTableSkeleton />
: <DataTable columns={followersColumns} data={followers} />
}
</div>
</div>
);
};

View File

@ -1,173 +0,0 @@
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/common/Button';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/common/Dialog';
export const InstructionModal = () => {
const t = useTranslations('dashboard.keys.instructionModal');
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="secondary">
{t('trigger')}
</Button>
</DialogTrigger>
<DialogContent className="max-h-[80vh] max-w-[800px] overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-xl">
{t('heading')}
</DialogTitle>
<DialogDescription className="text-sm text-muted-foreground">
{t('description')}
</DialogDescription>
</DialogHeader>
<h2 className="text-lg font-semibold">
{t('step1Title')}
</h2>
<p className="text-sm text-muted-foreground">
{t('step1Description')}
</p>
<ol className="list-inside list-decimal space-y-2 pl-4">
<li className="text-sm text-muted-foreground">
<strong>
{t('downloadObs')}
</strong>
<br />
{t('downloadObsDescription')}
{' '}
<a
className="text-blue-500 underline hover:text-blue-700"
href="https://obsproject.com"
rel="noopener noreferrer"
target="_blank"
>
{t('obsLinkText')}
</a>
.
</li>
<li className="text-sm text-muted-foreground">
<strong>
{t('copyKeys')}
</strong>
<br />
{t('copyKeysDescription')}
</li>
</ol>
<h2 className="mt-4 text-lg font-semibold">
{t('step2Title')}
</h2>
<p className="text-sm text-muted-foreground">
{t('step2Description')}
</p>
<ol className="list-inside list-decimal space-y-2 pl-4">
<li className="text-sm text-muted-foreground">
<strong>
{t('openObs')}
</strong>
<br />
{t('openObsDescription')}
</li>
<li className="text-sm text-muted-foreground">
<strong>
{t('openStreamSettings')}
</strong>
<br />
{t('openStreamSettingsDescription')}
</li>
<li className="text-sm text-muted-foreground">
<strong>
{t('enterDetails')}
</strong>
<br />
{t('enterDetailsDescription')}
</li>
<li className="text-sm text-muted-foreground">
<strong>
{t('saveSettings')}
</strong>
<br />
{t('saveSettingsDescription')}
</li>
</ol>
<h2 className="mt-4 text-lg font-semibold">
{t('step3Title')}
</h2>
<p className="text-sm text-muted-foreground">
{t('step3Description')}
</p>
<ol className="list-inside list-decimal space-y-2 pl-4">
<li className="text-sm text-muted-foreground">
<strong>
{t('startStream')}
</strong>
<br />
{t('startStreamDescription')}
</li>
<li className="text-sm text-muted-foreground">
<strong>
{t('monitorStream')}
</strong>
<br />
{t('monitorStreamDescription')}
</li>
</ol>
<p className="mt-4 text-sm text-muted-foreground">
{t('congrats')}
</p>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">
{t('close')}
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

View File

@ -1,51 +0,0 @@
'use client';
import { useTranslations } from 'next-intl';
import { Heading } from '@/components/ui/elements/Heading';
import { ToggleCardSkeleton } from '@/components/ui/elements/ToggleCard';
import { useCurrent } from '@/hooks/useCurrent';
import { CreateIngressForm } from './forms/CreateIngressForm';
import { StreamKey } from './forms/StreamKey';
import { StreamURL } from './forms/StreamURL';
import { InstructionModal } from './InstructionModal';
export const KeysSettings = () => {
const t = useTranslations('dashboard.keys.header');
const { user, isLoadingProfile } = useCurrent();
return (
<div className="lg:px-10">
<div className="block items-center justify-between space-y-3 lg:flex lg:space-y-0">
<Heading
description={t('description')}
size="lg"
title={t('heading')}
/>
<div className="flex items-center gap-x-4">
<InstructionModal />
<CreateIngressForm />
</div>
</div>
<div className="mt-5 space-y-6">
{isLoadingProfile
? Array.from({ length: 2 }).map((_, index) => (
// eslint-disable-next-line react/no-array-index-key
<ToggleCardSkeleton key={index} />
))
: (
<>
<StreamURL value={user?.stream?.serverUrl} />
<StreamKey value={user?.stream?.key} />
</>
)}
</div>
</div>
);
};

View File

@ -1,149 +0,0 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { Button } from '@/components/ui/common/Button';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/common/Dialog';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
} from '@/components/ui/common/Form';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/common/Select';
import { useCreateIngressMutation } from '@/graphql/generated/output';
import { useCurrent } from '@/hooks/useCurrent';
import {
IngressType,
type TypeCreateIngressSchema,
createIngressSchema,
} from '@/schemas/stream/create-ingress.schema';
export const CreateIngressForm = () => {
const t = useTranslations('dashboard.keys.createModal');
const [isOpen, setIsOpen] = useState(false);
const { refetch } = useCurrent();
const form = useForm<TypeCreateIngressSchema>({
resolver: zodResolver(createIngressSchema),
defaultValues: {
ingressType: IngressType.RTMP,
},
});
const [create, { loading: isLoadingCreate }] = useCreateIngressMutation({
onCompleted() {
setIsOpen(false);
void refetch();
toast.success(t('successMessage'));
},
onError() {
toast.error(t('errorMessage'));
},
});
const { isValid } = form.formState;
function onSubmit(data: TypeCreateIngressSchema) {
void create({ variables: { ingressType: data.ingressType } });
}
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>
{t('trigger')}
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>
{t('heading')}
</DialogTitle>
</DialogHeader>
<Form {...form}>
<form
className="space-y-6"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control}
name="ingressType"
render={({ field }) => (
<FormItem>
<FormLabel>
{t('ingressTypeLabel')}
</FormLabel>
<FormControl>
<Select
defaultValue={field.value.toString()}
onValueChange={(value) => {
field.onChange(Number(value));
}}
>
<SelectTrigger>
<SelectValue
placeholder={t(
'ingressTypePlaceholder',
)}
/>
</SelectTrigger>
<SelectContent>
<SelectItem
disabled={isLoadingCreate}
value={IngressType.RTMP.toString()}
>
RTMP
</SelectItem>
<SelectItem
disabled={isLoadingCreate}
value={IngressType.WHIP.toString()}
>
WHIP
</SelectItem>
</SelectContent>
</Select>
</FormControl>
<FormDescription>
{t('ingressTypeDescription')}
</FormDescription>
</FormItem>
)}
/>
<div className="flex justify-end">
<Button disabled={!isValid || isLoadingCreate}>
{t('submitButton')}
</Button>
</div>
</form>
</Form>
</DialogContent>
</Dialog>
);
};

View File

@ -1,47 +0,0 @@
import { Eye, EyeOff } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { Button } from '@/components/ui/common/Button';
import { Input } from '@/components/ui/common/Input';
import { CardContainer } from '@/components/ui/elements/CardContainer';
import { CopyButton } from '@/components/ui/elements/CopyButton';
type StreamKeyProps = {
value?: string | null;
};
export const StreamKey = ({ value }: StreamKeyProps) => {
const t = useTranslations('dashboard.keys.key');
const [isShow, setIsShow] = useState(false);
const Icon = isShow ? Eye : EyeOff;
return (
<CardContainer
isRightContentFull
heading={t('heading')}
rightContent={(
<div className="flex w-full items-center gap-x-4">
<Input
disabled
placeholder={t('heading')}
type={isShow ? 'text' : 'password'}
value={value ?? ''}
/>
<CopyButton value={value} />
<Button
size="lgIcon"
variant="ghost"
onClick={() => { setIsShow(!isShow); }}
>
<Icon className="size-5" />
</Button>
</div>
)}
/>
);
};

View File

@ -1,31 +0,0 @@
import { useTranslations } from 'next-intl';
import { Input } from '@/components/ui/common/Input';
import { CardContainer } from '@/components/ui/elements/CardContainer';
import { CopyButton } from '@/components/ui/elements/CopyButton';
type StreamURLProps = {
value?: string | null;
};
export const StreamURL = ({ value }: StreamURLProps) => {
const t = useTranslations('dashboard.keys.url');
return (
<CardContainer
isRightContentFull
heading={t('heading')}
rightContent={(
<div className="flex w-full items-center gap-x-4">
<Input
disabled
placeholder={t('heading')}
value={value ?? ''}
/>
<CopyButton value={value} />
</div>
)}
/>
);
};

View File

@ -1,174 +0,0 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { Button } from '@/components/ui/common/Button';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/common/Dialog';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
} from '@/components/ui/common/Form';
import { Input } from '@/components/ui/common/Input';
import { Textarea } from '@/components/ui/common/Textarea';
import {
useCreateSponsorshipPlanMutation,
useFindMySponsorshipPlansQuery,
} from '@/graphql/generated/output';
import {
type TypeCreatePlanSchema,
createPlanSchema,
} from '@/schemas/plan/create-plan.schema';
export const CreatePlanForm = () => {
const t = useTranslations('dashboard.plans.createForm');
const [isOpen, setIsOpen] = useState(false);
const { refetch } = useFindMySponsorshipPlansQuery();
const form = useForm<TypeCreatePlanSchema>({
resolver: zodResolver(createPlanSchema),
defaultValues: {
title: '',
description: '',
price: 0,
},
});
const [create, { loading: isLoadingCreate }] = useCreateSponsorshipPlanMutation({
onCompleted() {
setIsOpen(false);
form.reset();
void refetch();
toast.success(t('successMessage'));
},
onError() {
toast.error(t('errorMessage'));
},
});
const { isValid } = form.formState;
function onSubmit(data: TypeCreatePlanSchema) {
void create({ variables: { data } });
}
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>
{t('trigger')}
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>
{t('heading')}
</DialogTitle>
</DialogHeader>
<Form {...form}>
<form
className="space-y-6"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>
{t('titleLabel')}
</FormLabel>
<FormControl>
<Input
disabled={isLoadingCreate}
placeholder={t('titlePlaceholder')}
{...field}
/>
</FormControl>
<FormDescription>
{t('titleDescription')}
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>
{t('descriptionLabel')}
</FormLabel>
<FormControl>
<Textarea
disabled={isLoadingCreate}
placeholder={t(
'descriptionPlaceholder',
)}
{...field}
/>
</FormControl>
<FormDescription>
{t('descriptionDescription')}
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="price"
render={({ field }) => (
<FormItem>
<FormLabel>
{t('priceLabel')}
</FormLabel>
<FormControl>
<Input
disabled={isLoadingCreate}
placeholder={t('priceLabel')}
type="number"
{...field}
/>
</FormControl>
<FormDescription>
{t('priceDescription')}
</FormDescription>
</FormItem>
)}
/>
<div className="flex justify-end">
<Button disabled={!isValid || isLoadingCreate}>
{t('submitButton')}
</Button>
</div>
</form>
</Form>
</DialogContent>
</Dialog>
);
};

View File

@ -1,135 +0,0 @@
'use client';
import { MoreHorizontal, Trash } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import { Button } from '@/components/ui/common/Button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/common/DropdownMenu';
import {
DataTable,
DataTableSkeleton,
} from '@/components/ui/elements/DataTable';
import { Heading } from '@/components/ui/elements/Heading';
import {
type FindMySponsorshipPlansQuery,
useFindMySponsorshipPlansQuery,
useRemoveSponsorshipPlanMutation,
} from '@/graphql/generated/output';
import { useCurrent } from '@/hooks/useCurrent';
import { convertPrice } from '@/utils/convert-price';
import { formatDate } from '@/utils/format-date';
import { CreatePlanForm } from '../forms/CreatePlanForm';
import { VerifiedChannelAlert } from './VerifiedChannelAlert';
import type { ColumnDef } from '@tanstack/react-table';
export const PlansTable = () => {
const t = useTranslations('dashboard.plans');
const { user } = useCurrent();
const {
data,
loading: isLoadingPlans,
refetch,
} = useFindMySponsorshipPlansQuery();
const plans = data?.findMySponsorshipPlans ?? [];
const plansColumns: ColumnDef<
FindMySponsorshipPlansQuery['findMySponsorshipPlans'][0]
>[] = [
{
accessorKey: 'createdAt',
header: t('columns.date'),
cell: ({ row }) => formatDate(row.original.createdAt),
},
{
accessorKey: 'title',
header: t('columns.title'),
cell: ({ row }) => row.original.title,
},
{
accessorKey: 'price',
header: t('columns.price'),
cell: ({ row }) => convertPrice(row.original.price),
},
{
accessorKey: 'actions',
header: t('columns.actions'),
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row }) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [remove, { loading: isLoadingRemove }] = useRemoveSponsorshipPlanMutation({
onCompleted() {
void refetch();
toast.success(t('columns.successMessage'));
},
onError() {
// @ts-ignore
toast.error(t('columns.errorMessage'));
},
});
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="size-8 p-0" variant="ghost">
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right">
<DropdownMenuItem
className="text-red-500 focus:text-red-500"
disabled={isLoadingRemove}
onClick={async () => remove({
variables: { planId: row.original.id },
})}
>
<Trash className="mr-2 size-4" />
{t('columns.remove')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];
return user?.isVerified
? (
<div className="lg:px-10">
<div className="block items-center justify-between space-y-3 lg:flex lg:space-y-0">
<Heading
description={t('header.description')}
size="lg"
title={t('header.heading')}
/>
<CreatePlanForm />
</div>
<div className="mt-5">
{isLoadingPlans
? (
<DataTableSkeleton />
)
: (
<DataTable columns={plansColumns} data={plans} />
)}
</div>
</div>
)
: (
<VerifiedChannelAlert />
);
};

View File

@ -1,20 +0,0 @@
import { ShieldAlert } from 'lucide-react';
import { useTranslations } from 'next-intl';
export const VerifiedChannelAlert = () => {
const t = useTranslations('dashboard.plans.alert');
return (
<div className="flex h-[75vh] w-full flex-col items-center justify-center">
<ShieldAlert className="size-20 text-muted-foreground" />
<h1 className="mt-6 text-2xl font-semibold">
{t('heading')}
</h1>
<p className="mt-3 w-full items-center text-center text-muted-foreground lg:w-[60%]">
{t('description')}
</p>
</div>
);
};

View File

@ -1,112 +0,0 @@
'use client';
import { MoreHorizontal, User } from 'lucide-react';
import Link from 'next/link';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/common/Button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/common/DropdownMenu';
import { ChannelAvatar } from '@/components/ui/elements/ChannelAvatar';
import { ChannelVerified } from '@/components/ui/elements/ChannelVerified';
import {
DataTable,
DataTableSkeleton,
} from '@/components/ui/elements/DataTable';
import { Heading } from '@/components/ui/elements/Heading';
import {
type FindMySponsorsQuery,
useFindMySponsorsQuery,
} from '@/graphql/generated/output';
import { formatDate } from '@/utils/format-date';
import type { ColumnDef } from '@tanstack/react-table';
export const SponsorsTable = () => {
const t = useTranslations('dashboard.sponsors');
const { data, loading: isLoadingSponsors } = useFindMySponsorsQuery();
const sponsors = data?.findMySponsors ?? [];
const sponsorsColumns: ColumnDef<
FindMySponsorsQuery['findMySponsors'][0]
>[] = [
{
accessorKey: 'expiresAt',
header: t('columns.date'),
cell: ({ row }) => formatDate(row.original.expiresAt),
},
{
accessorKey: 'user',
header: t('columns.user'),
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row }) => (
<div className="flex items-center gap-x-2">
<ChannelAvatar channel={row.original.user} size="sm" />
<h2>
{row.original.user.name}
</h2>
{row.original.user.isVerified ? <ChannelVerified size="sm" /> : null}
</div>
),
},
{
accessorKey: 'plan',
header: t('columns.plan'),
cell: ({ row }) => row.original.plan.title,
},
{
accessorKey: 'actions',
header: t('columns.actions'),
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row }) => (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="size-8 p-0" variant="ghost">
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right">
<Link
href={`/${row.original.user.name}`}
target="_blank"
>
<DropdownMenuItem>
<User className="mr-2 size-4" />
{t('columns.viewChannel')}
</DropdownMenuItem>
</Link>
</DropdownMenuContent>
</DropdownMenu>
),
},
];
return (
<div className="lg:px-10">
<Heading
description={t('header.description')}
size="lg"
title={t('header.heading')}
/>
<div className="mt-5">
{isLoadingSponsors
? (
<DataTableSkeleton />
)
: (
<DataTable columns={sponsorsColumns} data={sponsors} />
)}
</div>
</div>
);
};

View File

@ -1,115 +0,0 @@
'use client';
import { useTranslations } from 'next-intl';
import {
DataTable,
DataTableSkeleton,
} from '@/components/ui/elements/DataTable';
import { Heading } from '@/components/ui/elements/Heading';
import {
type FindMyTransactionsQuery,
TransactionStatus,
useFindMyTransactionsQuery,
} from '@/graphql/generated/output';
import { convertPrice } from '@/utils/convert-price';
import { formatDate } from '@/utils/format-date';
import type { ColumnDef } from '@tanstack/react-table';
export const TransactionsTable = () => {
const t = useTranslations('dashboard.transactions');
const { data, loading: isLoadingTransactions } = useFindMyTransactionsQuery();
const transactions = data?.findMyTransactions ?? [];
const transactionsColumns: ColumnDef<
FindMyTransactionsQuery['findMyTransactions'][0]
>[] = [
{
accessorKey: 'createdAt',
header: t('columns.date'),
cell: ({ row }) => formatDate(row.original.createdAt),
},
{
accessorKey: 'status',
header: t('columns.status'),
// eslint-disable-next-line react/no-unstable-nested-components
cell: ({ row }) => {
const { status } = row.original;
// eslint-disable-next-line no-useless-assignment
let statusColor = '';
switch (status) {
case TransactionStatus.Success:
statusColor = 'text-green-500';
return (
<div className={`py-1.5 ${statusColor}`}>
{t('columns.success')}
</div>
);
case TransactionStatus.Pending:
statusColor = 'text-yellow-500';
return (
<div className={`py-1.5 ${statusColor}`}>
{t('columns.pending')}
</div>
);
case TransactionStatus.Failed:
statusColor = 'text-red-600';
return (
<div className={`py-1.5 ${statusColor}`}>
{t('columns.failed')}
</div>
);
case TransactionStatus.Expired:
statusColor = 'text-purple-500';
return (
<div className={`py-1.5 ${statusColor}`}>
{t('columns.expired')}
</div>
);
default:
statusColor = 'text-foreground';
return (
<div className={`py-1.5 ${statusColor}`}>
{status}
</div>
);
}
},
},
{
accessorKey: 'amount',
header: t('columns.amount'),
cell: ({ row }) => convertPrice(row.original.amount),
},
];
return (
<div className="lg:px-10">
<Heading
description={t('header.description')}
title={t('header.heading')}
/>
<div className="mt-5">
{isLoadingTransactions
? (
<DataTableSkeleton />
)
: (
<DataTable
columns={transactionsColumns}
data={transactions}
/>
)}
</div>
</div>
);
};

View File

@ -72,6 +72,7 @@ export const ChangeAvatarForm = () => {
return null; return null;
} }
return isLoadingProfile return isLoadingProfile
? ( ? (
<ChangeAvatarFormSkeleton /> <ChangeAvatarFormSkeleton />

View File

@ -1,124 +0,0 @@
import {
type HTMLAttributes,
type TdHTMLAttributes,
type ThHTMLAttributes,
forwardRef,
} from 'react';
import { cn } from '@/utils/tw-merge';
const Table = forwardRef<HTMLTableElement, HTMLAttributes<HTMLTableElement>>(
({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn('w-full caption-bottom text-sm', className)}
{...props}
/>
</div>
),
);
Table.displayName = 'Table';
const TableHeader = forwardRef<
HTMLTableSectionElement,
HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
));
TableHeader.displayName = 'TableHeader';
const TableBody = forwardRef<
HTMLTableSectionElement,
HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn('[&_tr:last-child]:border-0', className)}
{...props}
/>
));
TableBody.displayName = 'TableBody';
const TableFooter = forwardRef<
HTMLTableSectionElement,
HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
className,
)}
{...props}
/>
));
TableFooter.displayName = 'TableFooter';
const TableRow = forwardRef<
HTMLTableRowElement,
HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
'border-b transition-colors hover:bg-card data-[state=selected]:bg-muted',
className,
)}
{...props}
/>
));
TableRow.displayName = 'TableRow';
const TableHead = forwardRef<
HTMLTableCellElement,
ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
className,
)}
{...props}
/>
));
TableHead.displayName = 'TableHead';
const TableCell = forwardRef<
HTMLTableCellElement,
TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn(
'px-4 py-2 align-middle [&:has([role=checkbox])]:pr-0',
className,
)}
{...props}
/>
));
TableCell.displayName = 'TableCell';
const TableCaption = forwardRef<
HTMLTableCaptionElement,
HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn('mt-4 text-sm text-muted-foreground', className)}
{...props}
/>
));
TableCaption.displayName = 'TableCaption';
export {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
};

View File

@ -1,40 +0,0 @@
import { Check, Copy } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { toast } from 'sonner';
import { Button } from '../common/Button';
type CopyButtonProps = {
value?: string | null;
};
export const CopyButton = ({ value }: CopyButtonProps) => {
const t = useTranslations('components.copyButton');
const [isCopied, setIsCopied] = useState(false);
function onCopy() {
if (!value) return;
setIsCopied(true);
void navigator.clipboard.writeText(value);
toast.success(t('successMessage'));
setTimeout(() => {
setIsCopied(false);
}, 2000);
}
const Icon = isCopied ? Check : Copy;
return (
<Button
disabled={!value || isCopied}
size="lgIcon"
variant="ghost"
onClick={() => { onCopy(); }}
>
<Icon className="size-5" />
</Button>
);
};

View File

@ -1,99 +0,0 @@
'use client';
import {
type ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import { Loader } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { Card } from '../common/Card';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '../common/Table';
type DataTableProps<TData, TValue> = {
columns: ColumnDef<TData, TValue>[];
data: TData[];
};
export const DataTable = <TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) => {
const t = useTranslations('components.dataTable');
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<div className="rounded-lg border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef
.header,
header.getContext(),
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length
? table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))
: (
<TableRow>
<TableCell
className="h-24 text-center"
colSpan={columns.length}
>
{t('notFound')}
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
};
export const DataTableSkeleton = () => (
<div className="mx-auto mb-10 w-full max-w-(--breakpoint-2xl)">
<Card className="mt-6 flex h-[500px] w-full items-center justify-center">
<Loader className="size-8 animate-spin text-muted-foreground" />
</Card>
</div>
);

View File

@ -643,48 +643,6 @@ export type VerifyAccountMutationVariables = Exact<{
export type VerifyAccountMutation = { __typename?: 'Mutation', verifyAccount: { __typename?: 'AuthModel', message?: string | null, user?: { __typename?: 'UserModel', isEmailVerified: boolean } | null } }; export type VerifyAccountMutation = { __typename?: 'Mutation', verifyAccount: { __typename?: 'AuthModel', message?: string | null, user?: { __typename?: 'UserModel', isEmailVerified: boolean } | null } };
export type ChangeChatSettingsMutationVariables = Exact<{
data: ChangeChatSettingsInput;
}>;
export type ChangeChatSettingsMutation = { __typename?: 'Mutation', changeChatSettings: { __typename?: 'StreamModel', id: string } };
export type SendChatMessageMutationVariables = Exact<{
data: SendMessageInput;
}>;
export type SendChatMessageMutation = { __typename?: 'Mutation', sendChatMessage: { __typename?: 'ChatMessageModel', streamId: string } };
export type CreateSponsorshipPlanMutationVariables = Exact<{
data: CreatePlanInput;
}>;
export type CreateSponsorshipPlanMutation = { __typename?: 'Mutation', createSponsorshipPlan: { __typename?: 'PlanModel', id: string } };
export type RemoveSponsorshipPlanMutationVariables = Exact<{
planId: Scalars['String']['input'];
}>;
export type RemoveSponsorshipPlanMutation = { __typename?: 'Mutation', removeSponsorshipPlan: { __typename?: 'PlanModel', id: string } };
export type MakePaymentMutationVariables = Exact<{
planId: Scalars['String']['input'];
}>;
export type MakePaymentMutation = { __typename?: 'Mutation', makePayment: { __typename?: 'MakePaymentModel', url: string } };
export type CreateIngressMutationVariables = Exact<{
ingressType: Scalars['Float']['input'];
}>;
export type CreateIngressMutation = { __typename?: 'Mutation', createIngress: boolean };
export type ChangeEmailMutationVariables = Exact<{ export type ChangeEmailMutationVariables = Exact<{
data: ChangeEmailInput; data: ChangeEmailInput;
}>; }>;
@ -785,31 +743,6 @@ export type FindRecommendedChannelsQueryVariables = Exact<{ [key: string]: never
export type FindRecommendedChannelsQuery = { __typename?: 'Query', findRecommendedChannels: Array<{ __typename?: 'UserModel', id: string, name: string, avatar?: string | null, isVerified: boolean, stream: { __typename?: 'StreamModel', isLive: boolean } }> }; export type FindRecommendedChannelsQuery = { __typename?: 'Query', findRecommendedChannels: Array<{ __typename?: 'UserModel', id: string, name: string, avatar?: string | null, isVerified: boolean, stream: { __typename?: 'StreamModel', isLive: boolean } }> };
export type FindMyFollowersQueryVariables = Exact<{ [key: string]: never; }>;
export type FindMyFollowersQuery = { __typename?: 'Query', findMyFollowers: Array<{ __typename?: 'FollowModel', createdAt: any, follower: { __typename?: 'UserModel', name: string, avatar?: string | null, isVerified: boolean } }> };
export type FindMyFollowingsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindMyFollowingsQuery = { __typename?: 'Query', findMyFollowings: Array<{ __typename?: 'FollowModel', createdAt: any, followingId: string }> };
export type FindMySponsorshipPlansQueryVariables = Exact<{ [key: string]: never; }>;
export type FindMySponsorshipPlansQuery = { __typename?: 'Query', findMySponsorshipPlans: Array<{ __typename?: 'PlanModel', id: string, createdAt: any, title: string, price: number }> };
export type FindMySponsorsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindMySponsorsQuery = { __typename?: 'Query', findMySponsors: Array<{ __typename?: 'SubscriptionModel', expiresAt: any, user: { __typename?: 'UserModel', name: string, avatar?: string | null, isVerified: boolean }, plan: { __typename?: 'PlanModel', title: string } }> };
export type FindMyTransactionsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindMyTransactionsQuery = { __typename?: 'Query', findMyTransactions: Array<{ __typename?: 'TransactionModel', createdAt: any, status: TransactionStatus, amount: number }> };
export type FindCurrentSessionQueryVariables = Exact<{ [key: string]: never; }>; export type FindCurrentSessionQueryVariables = Exact<{ [key: string]: never; }>;
@ -828,7 +761,7 @@ export type FindUnreadNotificationsCountQuery = { __typename?: 'Query', findUnre
export type FindProfileQueryVariables = Exact<{ [key: string]: never; }>; export type FindProfileQueryVariables = Exact<{ [key: string]: never; }>;
export type FindProfileQuery = { __typename?: 'Query', findProfile: { __typename?: 'UserModel', avatar?: string | null, bio?: string | null, createdAt: any, email: string, id: string, name: string, updatedAt: any, isEmailVerified: boolean, isTotpEnabled: boolean, isVerified: boolean, displayName: string, socialLink: Array<{ __typename?: 'SocialLinkModel', title: string, url: string, position: number }>, notificationSettings?: { __typename?: 'NotificationSettingsModel', siteNotifications: boolean, telegramNotifications: boolean } | null, stream: { __typename?: 'StreamModel', serverUrl?: string | null, key?: string | null, isChatEnable: boolean, isChatFollowersOnly: boolean, isChatPremiumFollowersOnly: boolean } } }; export type FindProfileQuery = { __typename?: 'Query', findProfile: { __typename?: 'UserModel', avatar?: string | null, bio?: string | null, createdAt: any, email: string, id: string, name: string, updatedAt: any, isEmailVerified: boolean, isTotpEnabled: boolean, isVerified: boolean, displayName: string, socialLink: Array<{ __typename?: 'SocialLinkModel', title: string, url: string, position: number }>, notificationSettings?: { __typename?: 'NotificationSettingsModel', siteNotifications: boolean, telegramNotifications: boolean } | null } };
export type FindSessionsByUserQueryVariables = Exact<{ [key: string]: never; }>; export type FindSessionsByUserQueryVariables = Exact<{ [key: string]: never; }>;
@ -1113,202 +1046,6 @@ export function useVerifyAccountMutation(baseOptions?: Apollo.MutationHookOption
export type VerifyAccountMutationHookResult = ReturnType<typeof useVerifyAccountMutation>; export type VerifyAccountMutationHookResult = ReturnType<typeof useVerifyAccountMutation>;
export type VerifyAccountMutationResult = Apollo.MutationResult<VerifyAccountMutation>; export type VerifyAccountMutationResult = Apollo.MutationResult<VerifyAccountMutation>;
export type VerifyAccountMutationOptions = Apollo.BaseMutationOptions<VerifyAccountMutation, VerifyAccountMutationVariables>; export type VerifyAccountMutationOptions = Apollo.BaseMutationOptions<VerifyAccountMutation, VerifyAccountMutationVariables>;
export const ChangeChatSettingsDocument = gql`
mutation ChangeChatSettings($data: ChangeChatSettingsInput!) {
changeChatSettings(data: $data) {
id
}
}
`;
export type ChangeChatSettingsMutationFn = Apollo.MutationFunction<ChangeChatSettingsMutation, ChangeChatSettingsMutationVariables>;
/**
* __useChangeChatSettingsMutation__
*
* To run a mutation, you first call `useChangeChatSettingsMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useChangeChatSettingsMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [changeChatSettingsMutation, { data, loading, error }] = useChangeChatSettingsMutation({
* variables: {
* data: // value for 'data'
* },
* });
*/
export function useChangeChatSettingsMutation(baseOptions?: Apollo.MutationHookOptions<ChangeChatSettingsMutation, ChangeChatSettingsMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<ChangeChatSettingsMutation, ChangeChatSettingsMutationVariables>(ChangeChatSettingsDocument, options);
}
export type ChangeChatSettingsMutationHookResult = ReturnType<typeof useChangeChatSettingsMutation>;
export type ChangeChatSettingsMutationResult = Apollo.MutationResult<ChangeChatSettingsMutation>;
export type ChangeChatSettingsMutationOptions = Apollo.BaseMutationOptions<ChangeChatSettingsMutation, ChangeChatSettingsMutationVariables>;
export const SendChatMessageDocument = gql`
mutation SendChatMessage($data: SendMessageInput!) {
sendChatMessage(data: $data) {
streamId
}
}
`;
export type SendChatMessageMutationFn = Apollo.MutationFunction<SendChatMessageMutation, SendChatMessageMutationVariables>;
/**
* __useSendChatMessageMutation__
*
* To run a mutation, you first call `useSendChatMessageMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useSendChatMessageMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [sendChatMessageMutation, { data, loading, error }] = useSendChatMessageMutation({
* variables: {
* data: // value for 'data'
* },
* });
*/
export function useSendChatMessageMutation(baseOptions?: Apollo.MutationHookOptions<SendChatMessageMutation, SendChatMessageMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<SendChatMessageMutation, SendChatMessageMutationVariables>(SendChatMessageDocument, options);
}
export type SendChatMessageMutationHookResult = ReturnType<typeof useSendChatMessageMutation>;
export type SendChatMessageMutationResult = Apollo.MutationResult<SendChatMessageMutation>;
export type SendChatMessageMutationOptions = Apollo.BaseMutationOptions<SendChatMessageMutation, SendChatMessageMutationVariables>;
export const CreateSponsorshipPlanDocument = gql`
mutation CreateSponsorshipPlan($data: CreatePlanInput!) {
createSponsorshipPlan(data: $data) {
id
}
}
`;
export type CreateSponsorshipPlanMutationFn = Apollo.MutationFunction<CreateSponsorshipPlanMutation, CreateSponsorshipPlanMutationVariables>;
/**
* __useCreateSponsorshipPlanMutation__
*
* To run a mutation, you first call `useCreateSponsorshipPlanMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateSponsorshipPlanMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createSponsorshipPlanMutation, { data, loading, error }] = useCreateSponsorshipPlanMutation({
* variables: {
* data: // value for 'data'
* },
* });
*/
export function useCreateSponsorshipPlanMutation(baseOptions?: Apollo.MutationHookOptions<CreateSponsorshipPlanMutation, CreateSponsorshipPlanMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<CreateSponsorshipPlanMutation, CreateSponsorshipPlanMutationVariables>(CreateSponsorshipPlanDocument, options);
}
export type CreateSponsorshipPlanMutationHookResult = ReturnType<typeof useCreateSponsorshipPlanMutation>;
export type CreateSponsorshipPlanMutationResult = Apollo.MutationResult<CreateSponsorshipPlanMutation>;
export type CreateSponsorshipPlanMutationOptions = Apollo.BaseMutationOptions<CreateSponsorshipPlanMutation, CreateSponsorshipPlanMutationVariables>;
export const RemoveSponsorshipPlanDocument = gql`
mutation RemoveSponsorshipPlan($planId: String!) {
removeSponsorshipPlan(planId: $planId) {
id
}
}
`;
export type RemoveSponsorshipPlanMutationFn = Apollo.MutationFunction<RemoveSponsorshipPlanMutation, RemoveSponsorshipPlanMutationVariables>;
/**
* __useRemoveSponsorshipPlanMutation__
*
* To run a mutation, you first call `useRemoveSponsorshipPlanMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRemoveSponsorshipPlanMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [removeSponsorshipPlanMutation, { data, loading, error }] = useRemoveSponsorshipPlanMutation({
* variables: {
* planId: // value for 'planId'
* },
* });
*/
export function useRemoveSponsorshipPlanMutation(baseOptions?: Apollo.MutationHookOptions<RemoveSponsorshipPlanMutation, RemoveSponsorshipPlanMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<RemoveSponsorshipPlanMutation, RemoveSponsorshipPlanMutationVariables>(RemoveSponsorshipPlanDocument, options);
}
export type RemoveSponsorshipPlanMutationHookResult = ReturnType<typeof useRemoveSponsorshipPlanMutation>;
export type RemoveSponsorshipPlanMutationResult = Apollo.MutationResult<RemoveSponsorshipPlanMutation>;
export type RemoveSponsorshipPlanMutationOptions = Apollo.BaseMutationOptions<RemoveSponsorshipPlanMutation, RemoveSponsorshipPlanMutationVariables>;
export const MakePaymentDocument = gql`
mutation MakePayment($planId: String!) {
makePayment(planId: $planId) {
url
}
}
`;
export type MakePaymentMutationFn = Apollo.MutationFunction<MakePaymentMutation, MakePaymentMutationVariables>;
/**
* __useMakePaymentMutation__
*
* To run a mutation, you first call `useMakePaymentMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useMakePaymentMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [makePaymentMutation, { data, loading, error }] = useMakePaymentMutation({
* variables: {
* planId: // value for 'planId'
* },
* });
*/
export function useMakePaymentMutation(baseOptions?: Apollo.MutationHookOptions<MakePaymentMutation, MakePaymentMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<MakePaymentMutation, MakePaymentMutationVariables>(MakePaymentDocument, options);
}
export type MakePaymentMutationHookResult = ReturnType<typeof useMakePaymentMutation>;
export type MakePaymentMutationResult = Apollo.MutationResult<MakePaymentMutation>;
export type MakePaymentMutationOptions = Apollo.BaseMutationOptions<MakePaymentMutation, MakePaymentMutationVariables>;
export const CreateIngressDocument = gql`
mutation CreateIngress($ingressType: Float!) {
createIngress(ingressType: $ingressType)
}
`;
export type CreateIngressMutationFn = Apollo.MutationFunction<CreateIngressMutation, CreateIngressMutationVariables>;
/**
* __useCreateIngressMutation__
*
* To run a mutation, you first call `useCreateIngressMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateIngressMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createIngressMutation, { data, loading, error }] = useCreateIngressMutation({
* variables: {
* ingressType: // value for 'ingressType'
* },
* });
*/
export function useCreateIngressMutation(baseOptions?: Apollo.MutationHookOptions<CreateIngressMutation, CreateIngressMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<CreateIngressMutation, CreateIngressMutationVariables>(CreateIngressDocument, options);
}
export type CreateIngressMutationHookResult = ReturnType<typeof useCreateIngressMutation>;
export type CreateIngressMutationResult = Apollo.MutationResult<CreateIngressMutation>;
export type CreateIngressMutationOptions = Apollo.BaseMutationOptions<CreateIngressMutation, CreateIngressMutationVariables>;
export const ChangeEmailDocument = gql` export const ChangeEmailDocument = gql`
mutation ChangeEmail($data: ChangeEmailInput!) { mutation ChangeEmail($data: ChangeEmailInput!) {
changeEmail(data: $data) { changeEmail(data: $data) {
@ -1821,220 +1558,6 @@ export type FindRecommendedChannelsQueryHookResult = ReturnType<typeof useFindRe
export type FindRecommendedChannelsLazyQueryHookResult = ReturnType<typeof useFindRecommendedChannelsLazyQuery>; export type FindRecommendedChannelsLazyQueryHookResult = ReturnType<typeof useFindRecommendedChannelsLazyQuery>;
export type FindRecommendedChannelsSuspenseQueryHookResult = ReturnType<typeof useFindRecommendedChannelsSuspenseQuery>; export type FindRecommendedChannelsSuspenseQueryHookResult = ReturnType<typeof useFindRecommendedChannelsSuspenseQuery>;
export type FindRecommendedChannelsQueryResult = Apollo.QueryResult<FindRecommendedChannelsQuery, FindRecommendedChannelsQueryVariables>; export type FindRecommendedChannelsQueryResult = Apollo.QueryResult<FindRecommendedChannelsQuery, FindRecommendedChannelsQueryVariables>;
export const FindMyFollowersDocument = gql`
query FindMyFollowers {
findMyFollowers {
createdAt
follower {
name
avatar
isVerified
}
}
}
`;
/**
* __useFindMyFollowersQuery__
*
* To run a query within a React component, call `useFindMyFollowersQuery` and pass it any options that fit your needs.
* When your component renders, `useFindMyFollowersQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFindMyFollowersQuery({
* variables: {
* },
* });
*/
export function useFindMyFollowersQuery(baseOptions?: Apollo.QueryHookOptions<FindMyFollowersQuery, FindMyFollowersQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FindMyFollowersQuery, FindMyFollowersQueryVariables>(FindMyFollowersDocument, options);
}
export function useFindMyFollowersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindMyFollowersQuery, FindMyFollowersQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FindMyFollowersQuery, FindMyFollowersQueryVariables>(FindMyFollowersDocument, options);
}
export function useFindMyFollowersSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<FindMyFollowersQuery, FindMyFollowersQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<FindMyFollowersQuery, FindMyFollowersQueryVariables>(FindMyFollowersDocument, options);
}
export type FindMyFollowersQueryHookResult = ReturnType<typeof useFindMyFollowersQuery>;
export type FindMyFollowersLazyQueryHookResult = ReturnType<typeof useFindMyFollowersLazyQuery>;
export type FindMyFollowersSuspenseQueryHookResult = ReturnType<typeof useFindMyFollowersSuspenseQuery>;
export type FindMyFollowersQueryResult = Apollo.QueryResult<FindMyFollowersQuery, FindMyFollowersQueryVariables>;
export const FindMyFollowingsDocument = gql`
query FindMyFollowings {
findMyFollowings {
createdAt
followingId
}
}
`;
/**
* __useFindMyFollowingsQuery__
*
* To run a query within a React component, call `useFindMyFollowingsQuery` and pass it any options that fit your needs.
* When your component renders, `useFindMyFollowingsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFindMyFollowingsQuery({
* variables: {
* },
* });
*/
export function useFindMyFollowingsQuery(baseOptions?: Apollo.QueryHookOptions<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>(FindMyFollowingsDocument, options);
}
export function useFindMyFollowingsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>(FindMyFollowingsDocument, options);
}
export function useFindMyFollowingsSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>(FindMyFollowingsDocument, options);
}
export type FindMyFollowingsQueryHookResult = ReturnType<typeof useFindMyFollowingsQuery>;
export type FindMyFollowingsLazyQueryHookResult = ReturnType<typeof useFindMyFollowingsLazyQuery>;
export type FindMyFollowingsSuspenseQueryHookResult = ReturnType<typeof useFindMyFollowingsSuspenseQuery>;
export type FindMyFollowingsQueryResult = Apollo.QueryResult<FindMyFollowingsQuery, FindMyFollowingsQueryVariables>;
export const FindMySponsorshipPlansDocument = gql`
query FindMySponsorshipPlans {
findMySponsorshipPlans {
id
createdAt
title
price
}
}
`;
/**
* __useFindMySponsorshipPlansQuery__
*
* To run a query within a React component, call `useFindMySponsorshipPlansQuery` and pass it any options that fit your needs.
* When your component renders, `useFindMySponsorshipPlansQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFindMySponsorshipPlansQuery({
* variables: {
* },
* });
*/
export function useFindMySponsorshipPlansQuery(baseOptions?: Apollo.QueryHookOptions<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>(FindMySponsorshipPlansDocument, options);
}
export function useFindMySponsorshipPlansLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>(FindMySponsorshipPlansDocument, options);
}
export function useFindMySponsorshipPlansSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>(FindMySponsorshipPlansDocument, options);
}
export type FindMySponsorshipPlansQueryHookResult = ReturnType<typeof useFindMySponsorshipPlansQuery>;
export type FindMySponsorshipPlansLazyQueryHookResult = ReturnType<typeof useFindMySponsorshipPlansLazyQuery>;
export type FindMySponsorshipPlansSuspenseQueryHookResult = ReturnType<typeof useFindMySponsorshipPlansSuspenseQuery>;
export type FindMySponsorshipPlansQueryResult = Apollo.QueryResult<FindMySponsorshipPlansQuery, FindMySponsorshipPlansQueryVariables>;
export const FindMySponsorsDocument = gql`
query FindMySponsors {
findMySponsors {
expiresAt
user {
name
avatar
isVerified
}
plan {
title
}
}
}
`;
/**
* __useFindMySponsorsQuery__
*
* To run a query within a React component, call `useFindMySponsorsQuery` and pass it any options that fit your needs.
* When your component renders, `useFindMySponsorsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFindMySponsorsQuery({
* variables: {
* },
* });
*/
export function useFindMySponsorsQuery(baseOptions?: Apollo.QueryHookOptions<FindMySponsorsQuery, FindMySponsorsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FindMySponsorsQuery, FindMySponsorsQueryVariables>(FindMySponsorsDocument, options);
}
export function useFindMySponsorsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindMySponsorsQuery, FindMySponsorsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FindMySponsorsQuery, FindMySponsorsQueryVariables>(FindMySponsorsDocument, options);
}
export function useFindMySponsorsSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<FindMySponsorsQuery, FindMySponsorsQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<FindMySponsorsQuery, FindMySponsorsQueryVariables>(FindMySponsorsDocument, options);
}
export type FindMySponsorsQueryHookResult = ReturnType<typeof useFindMySponsorsQuery>;
export type FindMySponsorsLazyQueryHookResult = ReturnType<typeof useFindMySponsorsLazyQuery>;
export type FindMySponsorsSuspenseQueryHookResult = ReturnType<typeof useFindMySponsorsSuspenseQuery>;
export type FindMySponsorsQueryResult = Apollo.QueryResult<FindMySponsorsQuery, FindMySponsorsQueryVariables>;
export const FindMyTransactionsDocument = gql`
query FindMyTransactions {
findMyTransactions {
createdAt
status
amount
}
}
`;
/**
* __useFindMyTransactionsQuery__
*
* To run a query within a React component, call `useFindMyTransactionsQuery` and pass it any options that fit your needs.
* When your component renders, `useFindMyTransactionsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useFindMyTransactionsQuery({
* variables: {
* },
* });
*/
export function useFindMyTransactionsQuery(baseOptions?: Apollo.QueryHookOptions<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>(FindMyTransactionsDocument, options);
}
export function useFindMyTransactionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>(FindMyTransactionsDocument, options);
}
export function useFindMyTransactionsSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>(FindMyTransactionsDocument, options);
}
export type FindMyTransactionsQueryHookResult = ReturnType<typeof useFindMyTransactionsQuery>;
export type FindMyTransactionsLazyQueryHookResult = ReturnType<typeof useFindMyTransactionsLazyQuery>;
export type FindMyTransactionsSuspenseQueryHookResult = ReturnType<typeof useFindMyTransactionsSuspenseQuery>;
export type FindMyTransactionsQueryResult = Apollo.QueryResult<FindMyTransactionsQuery, FindMyTransactionsQueryVariables>;
export const FindCurrentSessionDocument = gql` export const FindCurrentSessionDocument = gql`
query FindCurrentSession { query FindCurrentSession {
findCurrentSession { findCurrentSession {
@ -2193,13 +1716,6 @@ export const FindProfileDocument = gql`
siteNotifications siteNotifications
telegramNotifications telegramNotifications
} }
stream {
serverUrl
key
isChatEnable
isChatFollowersOnly
isChatPremiumFollowersOnly
}
} }
} }
`; `;

View File

@ -1,5 +0,0 @@
mutation ChangeChatSettings($data: ChangeChatSettingsInput!) {
changeChatSettings(data: $data) {
id
}
}

View File

@ -1,5 +0,0 @@
mutation SendChatMessage($data: SendMessageInput!) {
sendChatMessage(data: $data) {
streamId
}
}

View File

@ -1,5 +0,0 @@
mutation CreateSponsorshipPlan($data: CreatePlanInput!) {
createSponsorshipPlan(data: $data) {
id
}
}

View File

@ -1,5 +0,0 @@
mutation RemoveSponsorshipPlan($planId: String!) {
removeSponsorshipPlan(planId: $planId) {
id
}
}

View File

@ -1,5 +0,0 @@
mutation MakePayment($planId: String!) {
makePayment(planId: $planId) {
url
}
}

View File

@ -1,3 +0,0 @@
mutation CreateIngress($ingressType: Float!) {
createIngress(ingressType: $ingressType)
}

View File

@ -1,10 +0,0 @@
query FindMyFollowers {
findMyFollowers {
createdAt
follower {
name
avatar
isVerified
}
}
}

View File

@ -1,6 +0,0 @@
query FindMyFollowings {
findMyFollowings {
createdAt
followingId
}
}

View File

@ -1,8 +0,0 @@
query FindMySponsorshipPlans {
findMySponsorshipPlans {
id
createdAt
title
price
}
}

View File

@ -1,13 +0,0 @@
query FindMySponsors {
findMySponsors {
expiresAt
user {
name
avatar
isVerified
}
plan {
title
}
}
}

View File

@ -1,7 +0,0 @@
query FindMyTransactions {
findMyTransactions {
createdAt
status
amount
}
}

View File

@ -20,12 +20,5 @@ query FindProfile {
siteNotifications siteNotifications
telegramNotifications telegramNotifications
} }
stream {
serverUrl
key
isChatEnable
isChatFollowersOnly
isChatPremiumFollowersOnly
}
} }
} }

View File

@ -2,17 +2,15 @@ import { ApolloClient, InMemoryCache, split } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws'; import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities'; import { getMainDefinition } from '@apollo/client/utilities';
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs'; import createUploadLink from 'apollo-upload-client/createUploadLink.mjs';
import { OperationTypeNode } from 'graphql/language';
import { Kind } from 'graphql/language/kinds';
import { SERVER_URL, WEBSOCKET_URL } from './constants/url.constants'; import { SERVER_URL, WEBSOCKET_URL } from './constants/url.constants';
const httpLink = createUploadLink({ const httpLink = createUploadLink({
uri: SERVER_URL, uri: SERVER_URL,
credentials: 'include', credentials: 'include',
headers: { // headers: {
'apollo-require-preflight': 'true', // 'apollo-require-preflight': 'true',
}, // },
}); });
const wsLink = new WebSocketLink({ const wsLink = new WebSocketLink({
@ -27,8 +25,8 @@ const splitLink = split(
const definition = getMainDefinition(query); const definition = getMainDefinition(query);
return ( return (
definition.kind === Kind.OPERATION_DEFINITION definition.kind === 'OperationDefinition'
&& definition.operation === OperationTypeNode.SUBSCRIPTION && definition.operation === 'subscription'
); );
}, },
wsLink, wsLink,

View File

@ -1,3 +1,3 @@
export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL as string; export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL as string;
export const WEBSOCKET_URL = process.env.NEXT_PUBLIC_WEBSOCKET_URL as string; export const WEBSOCKET_URL = process.env.NEXT_PUBLIC_WEBSOCKET_URL as string
export const MEDIA_URL = process.env.NEXT_PUBLIC_MEDIA_URL as string; export const MEDIA_URL = process.env.NEXT_PUBLIC_MEDIA_URL as string;

View File

@ -1,11 +0,0 @@
import { z } from 'zod';
export const changeChatSettingsSchema = z.object({
isChatEnable: z.boolean(),
isChatFollowersOnly: z.boolean(),
isChatPremiumFollowersOnly: z.boolean(),
});
export type TypeChangeChatSettingsSchema = z.infer<
typeof changeChatSettingsSchema
>;

View File

@ -1,7 +0,0 @@
import { z } from 'zod';
export const sendMessageSchema = z.object({
text: z.string().min(1),
});
export type TypeSendMessageSchema = z.infer<typeof sendMessageSchema>;

View File

@ -1,9 +0,0 @@
import { z } from 'zod';
export const createPlanSchema = z.object({
title: z.string().min(1),
description: z.string().optional(),
price: z.number().positive(),
});
export type TypeCreatePlanSchema = z.infer<typeof createPlanSchema>;

View File

@ -1,12 +0,0 @@
import { z } from 'zod';
export enum IngressType {
RTMP = 0,
WHIP = 1,
}
export const createIngressSchema = z.object({
ingressType: z.enum(IngressType),
});
export type TypeCreateIngressSchema = z.infer<typeof createIngressSchema>;

View File

@ -1,6 +0,0 @@
export function convertPrice(price: number) {
return price.toLocaleString('ru-RU', {
style: 'currency',
currency: 'RUB',
});
}

View File

@ -15,7 +15,7 @@
"@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/trace-mapping" "^0.3.24"
"@apollo/client@3.13.9", "@apollo/client@^3.8.0": "@apollo/client@3.13.9":
version "3.13.9" version "3.13.9"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.13.9.tgz#311e0df1734aaa5598e01a292bb7982df49cc062" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.13.9.tgz#311e0df1734aaa5598e01a292bb7982df49cc062"
integrity sha512-RStSzQfL1XwL6/NWd7W8avhGQYTgPCtJ+qHkkTTSj9Upp3VVm6Oppv81YWdXG1FgEpDPW4hvCrTUELdcC4inCQ== integrity sha512-RStSzQfL1XwL6/NWd7W8avhGQYTgPCtJ+qHkkTTSj9Upp3VVm6Oppv81YWdXG1FgEpDPW4hvCrTUELdcC4inCQ==
@ -2169,18 +2169,6 @@
postcss "^8.4.41" postcss "^8.4.41"
tailwindcss "4.1.11" tailwindcss "4.1.11"
"@tanstack/react-table@8.21.3":
version "8.21.3"
resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.21.3.tgz#2c38c747a5731c1a07174fda764b9c2b1fb5e91b"
integrity sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==
dependencies:
"@tanstack/table-core" "8.21.3"
"@tanstack/table-core@8.21.3":
version "8.21.3"
resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.21.3.tgz#2977727d8fc8dfa079112d9f4d4c019110f1732c"
integrity sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==
"@theguild/federation-composition@^0.19.0": "@theguild/federation-composition@^0.19.0":
version "0.19.1" version "0.19.1"
resolved "https://registry.yarnpkg.com/@theguild/federation-composition/-/federation-composition-0.19.1.tgz#b3907bfcbdbd69d4628a3b1270936615f56b904f" resolved "https://registry.yarnpkg.com/@theguild/federation-composition/-/federation-composition-0.19.1.tgz#b3907bfcbdbd69d4628a3b1270936615f56b904f"
@ -2225,25 +2213,11 @@
dependencies: dependencies:
tslib "^2.4.0" tslib "^2.4.0"
"@types/apollo-upload-client@18.0.0":
version "18.0.0"
resolved "https://registry.yarnpkg.com/@types/apollo-upload-client/-/apollo-upload-client-18.0.0.tgz#1f7e2ff0c0e6508bc1bd19b2340339c7abd117c3"
integrity sha512-cMgITNemktxasqvp6jiPj15dv84n3FTMvMoYBP1+xonDS+0l6JygIJrj2LJh85rShRzTOOkrElrAsCXXARa3KA==
dependencies:
"@apollo/client" "^3.8.0"
"@types/extract-files" "*"
graphql "14 - 16"
"@types/estree@^1.0.6": "@types/estree@^1.0.6":
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
"@types/extract-files@*":
version "13.0.1"
resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-13.0.1.tgz#3ec057a3fa25f778245a76a17271d23b71ee31d7"
integrity sha512-/fRbzc2lAd7jDJSSnxWiUyXWjdUZZ4HbISLJzVgt1AvrdOa7U49YRPcvuCUywkmURZ7uwJOheDjx19itbQ5KvA==
"@types/js-yaml@^4.0.0": "@types/js-yaml@^4.0.0":
version "4.0.9" version "4.0.9"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
@ -4297,7 +4271,7 @@ graphql-ws@^6.0.6:
resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-6.0.6.tgz#e9c9ff85f4ddb5bbe6faa2721c0d27e6c11746d2" resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-6.0.6.tgz#e9c9ff85f4ddb5bbe6faa2721c0d27e6c11746d2"
integrity sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw== integrity sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==
"graphql@14 - 16", graphql@16.11.0: graphql@16.11.0:
version "16.11.0" version "16.11.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.11.0.tgz#96d17f66370678027fdf59b2d4c20b4efaa8a633" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.11.0.tgz#96d17f66370678027fdf59b2d4c20b4efaa8a633"
integrity sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw== integrity sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==