[frontend]: add chat settings page

This commit is contained in:
Sergey Krylov 2025-08-14 05:45:17 +03:00
parent 4c0e463aec
commit ed59327cb7
8 changed files with 267 additions and 1 deletions

View File

@ -0,0 +1,20 @@
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

@ -0,0 +1,132 @@
'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);
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

@ -643,6 +643,20 @@ export type VerifyAccountMutationVariables = Exact<{
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 CreateIngressMutationVariables = Exact<{
ingressType: Scalars['Float']['input'];
}>;
@ -768,7 +782,7 @@ export type FindUnreadNotificationsCountQuery = { __typename?: 'Query', findUnre
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 } } };
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 FindSessionsByUserQueryVariables = Exact<{ [key: string]: never; }>;
@ -1053,6 +1067,72 @@ export function useVerifyAccountMutation(baseOptions?: Apollo.MutationHookOption
export type VerifyAccountMutationHookResult = ReturnType<typeof useVerifyAccountMutation>;
export type VerifyAccountMutationResult = Apollo.MutationResult<VerifyAccountMutation>;
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 CreateIngressDocument = gql`
mutation CreateIngress($ingressType: Float!) {
createIngress(ingressType: $ingressType)
@ -1757,6 +1837,9 @@ export const FindProfileDocument = gql`
stream {
serverUrl
key
isChatEnable
isChatFollowersOnly
isChatPremiumFollowersOnly
}
}
}

View File

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

View File

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

View File

@ -23,6 +23,9 @@ query FindProfile {
stream {
serverUrl
key
isChatEnable
isChatFollowersOnly
isChatPremiumFollowersOnly
}
}
}

View File

@ -0,0 +1,11 @@
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

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