[frontend]: add sponsorship pages
This commit is contained in:
parent
0f16f9d209
commit
37c6b318a6
20
frontend/src/app/(site)/dashboard/plans/page.tsx
Normal file
20
frontend/src/app/(site)/dashboard/plans/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
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;
|
||||
20
frontend/src/app/(site)/dashboard/sponsors/page.tsx
Normal file
20
frontend/src/app/(site)/dashboard/sponsors/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
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;
|
||||
20
frontend/src/app/(site)/dashboard/transactions/page.tsx
Normal file
20
frontend/src/app/(site)/dashboard/transactions/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
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;
|
||||
@ -14,6 +14,5 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeactivatePage() {
|
||||
return <DeactivateForm />;
|
||||
}
|
||||
const DeactivatePage = () => <DeactivateForm />;
|
||||
export default DeactivatePage;
|
||||
|
||||
@ -63,7 +63,7 @@ export const DeactivateForm = () => {
|
||||
const { isValid } = form.formState;
|
||||
|
||||
function onSubmit(data: TypeDeactivateSchema) {
|
||||
deactivate({ variables: { data } });
|
||||
void deactivate({ variables: { data } });
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -47,7 +47,7 @@ export const ChangeChatSettings = () => {
|
||||
) {
|
||||
form.setValue(field, value);
|
||||
|
||||
update({
|
||||
void update({
|
||||
variables: {
|
||||
data: { ...form.getValues(), [field]: value },
|
||||
},
|
||||
|
||||
@ -0,0 +1,174 @@
|
||||
'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>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,135 @@
|
||||
'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 />
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,112 @@
|
||||
'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>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,115 @@
|
||||
'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>
|
||||
);
|
||||
};
|
||||
@ -72,7 +72,6 @@ export const ChangeAvatarForm = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return isLoadingProfile
|
||||
? (
|
||||
<ChangeAvatarFormSkeleton />
|
||||
|
||||
@ -657,6 +657,27 @@ export type SendChatMessageMutationVariables = Exact<{
|
||||
|
||||
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'];
|
||||
}>;
|
||||
@ -774,6 +795,21 @@ 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; }>;
|
||||
|
||||
|
||||
@ -1143,6 +1179,105 @@ export function useSendChatMessageMutation(baseOptions?: Apollo.MutationHookOpti
|
||||
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)
|
||||
@ -1770,6 +1905,136 @@ export type FindMyFollowingsQueryHookResult = ReturnType<typeof useFindMyFollowi
|
||||
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`
|
||||
query FindCurrentSession {
|
||||
findCurrentSession {
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
mutation CreateSponsorshipPlan($data: CreatePlanInput!) {
|
||||
createSponsorshipPlan(data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
mutation RemoveSponsorshipPlan($planId: String!) {
|
||||
removeSponsorshipPlan(planId: $planId) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
mutation MakePayment($planId: String!) {
|
||||
makePayment(planId: $planId) {
|
||||
url
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
query FindMySponsorshipPlans {
|
||||
findMySponsorshipPlans {
|
||||
id
|
||||
createdAt
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
query FindMySponsors {
|
||||
findMySponsors {
|
||||
expiresAt
|
||||
user {
|
||||
name
|
||||
avatar
|
||||
isVerified
|
||||
}
|
||||
plan {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
query FindMyTransactions {
|
||||
findMyTransactions {
|
||||
createdAt
|
||||
status
|
||||
amount
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@ import { ApolloClient, InMemoryCache, split } from '@apollo/client';
|
||||
import { WebSocketLink } from '@apollo/client/link/ws';
|
||||
import { getMainDefinition } from '@apollo/client/utilities';
|
||||
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';
|
||||
|
||||
@ -25,8 +27,8 @@ const splitLink = split(
|
||||
const definition = getMainDefinition(query);
|
||||
|
||||
return (
|
||||
definition.kind === 'OperationDefinition'
|
||||
&& definition.operation === 'subscription'
|
||||
definition.kind === Kind.OPERATION_DEFINITION
|
||||
&& definition.operation === OperationTypeNode.SUBSCRIPTION
|
||||
);
|
||||
},
|
||||
wsLink,
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
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;
|
||||
|
||||
9
frontend/src/schemas/plan/create-plan.schema.ts
Normal file
9
frontend/src/schemas/plan/create-plan.schema.ts
Normal file
@ -0,0 +1,9 @@
|
||||
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>;
|
||||
6
frontend/src/utils/convert-price.ts
Normal file
6
frontend/src/utils/convert-price.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export function convertPrice(price: number) {
|
||||
return price.toLocaleString('ru-RU', {
|
||||
style: 'currency',
|
||||
currency: 'RUB',
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user