feat: personal setting notification change

This commit is contained in:
shuai 2023-08-21 15:32:57 +08:00
parent 41f7b1b9cd
commit 80df5193c5
8 changed files with 125 additions and 41 deletions

View File

@ -962,9 +962,16 @@ ui:
placeholder: "City, Country"
notification:
heading: Notifications
email:
label: Email Notifications
radio: "Answers to your questions, comments, and more"
email: Email
inbox:
label: Inbox notifications
description: Answers to your questions, comments, invites, and more.
all_new_question:
label: All new questions
description: Get notified of all new questions. Up to 50 questions per week.
all_new_question_for_following_tags:
label: All new questions for following tags
description: Get notified of new questions for following tags.
account:
heading: Account
change_email_btn: Change email

View File

@ -57,7 +57,7 @@ export interface TagInfo extends TagBase {
main_tag_slug_name?: string;
excerpt?;
}
export interface QuestionParams extends ImgCodeReq{
export interface QuestionParams extends ImgCodeReq {
title: string;
url_title?: string;
content: string;
@ -589,3 +589,13 @@ export interface UserOauthConnectorItem {
binding: boolean;
external_id: string;
}
export interface NotificationConfigItem {
enable: boolean;
key: string;
}
export interface NotificationConfig {
all_new_question: NotificationConfigItem[];
all_new_question_for_following_tags: NotificationConfigItem[];
inbox: NotificationConfigItem[];
}

View File

@ -27,12 +27,13 @@ const Index: FC<Props> = ({
index: number,
) => {
const { name, checked } = evt.currentTarget;
const freshVal = checked ? enumValues?.[index] : '';
enumValues[index] = checked;
const state = {
...formData,
[name]: {
...formData[name],
value: freshVal,
value: enumValues,
isInvalid: false,
},
};
@ -51,7 +52,7 @@ const Index: FC<Props> = ({
name={fieldName}
id={`form-${String(item)}`}
label={enumNames?.[index]}
checked={(fieldObject?.value || '') === item}
checked={fieldObject?.value?.[index] || false}
feedback={fieldObject?.errorMsg}
feedbackType="invalid"
isInvalid={fieldObject?.isInvalid}

View File

@ -386,8 +386,13 @@ export const initFormData = (schema: JSONSchema): Type.FormDataType => {
const props: JSONSchema['properties'] = schema?.properties || {};
Object.keys(props).forEach((key) => {
const prop = props[key];
const defaultVal = prop?.default;
let defaultVal: any = '';
if (Array.isArray(prop.default) && prop.enum && prop.enum.length > 0) {
// for checkbox default values
defaultVal = prop.enum;
} else {
defaultVal = prop?.default;
}
formData[key] = {
value: defaultVal,
isInvalid: false,

View File

@ -30,7 +30,7 @@ export interface JSONSchema {
description?: string;
enum?: Array<string | boolean | number>;
enumNames?: string[];
default?: string | boolean | number;
default?: string | boolean | number | any[];
};
};
}

View File

@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next';
import { usePageTags } from '@/hooks';
import * as Type from '@/common/interface';
import { FollowingTags, CustomSidebar } from '@/components';
import { FollowingTags, CustomSidebar, Icon } from '@/components';
import {
useTagInfo,
useFollow,
@ -141,9 +141,16 @@ const Index: FC = () => {
<div className="box-ft">
{tagInfo.is_follower ? (
<Button variant="primary" onClick={() => toggleFollow()}>
{t('button_following')}
</Button>
<div>
<Button variant="primary" onClick={() => toggleFollow()}>
{t('button_following')}
</Button>
<Link
className="btn btn-outline-secondary ms-2"
to="/users/settings/notify">
<Icon name="bell-fill" />
</Link>
</div>
) : (
<Button
variant="outline-primary"

View File

@ -1,9 +1,9 @@
import React, { useState, FormEvent, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import type { FormDataType } from '@/common/interface';
import type { FormDataType, NotificationConfig } from '@/common/interface';
import { useToast } from '@/hooks';
import { setNotice, getLoggedUserInfo } from '@/services';
import { useGetNotificationConfig, putNotificationConfig } from '@/services';
import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
const Index = () => {
@ -11,46 +11,90 @@ const Index = () => {
const { t } = useTranslation('translation', {
keyPrefix: 'settings.notification',
});
const { data: configData } = useGetNotificationConfig();
const schema: JSONSchema = {
title: t('heading'),
properties: {
notice_switch: {
inbox: {
type: 'boolean',
title: t('email.label'),
default: false,
title: t('inbox.label'),
description: t('inbox.description'),
enum: configData?.inbox?.map((v) => v.enable),
default: configData?.inbox?.map((v) => v.enable),
enumNames: configData?.inbox?.map((v) => t(v.key)),
},
all_new_question: {
type: 'boolean',
title: t('all_new_question.label'),
description: t('all_new_question.description'),
enum: configData?.all_new_question?.map((v) => v.enable),
default: configData?.all_new_question?.map((v) => v.enable),
enumNames: configData?.all_new_question?.map((v) => t(v.key)),
},
all_new_question_for_following_tags: {
type: 'boolean',
title: t('all_new_question_for_following_tags.label'),
description: t('all_new_question_for_following_tags.description'),
enum: configData?.all_new_question_for_following_tags?.map(
(v) => v.enable,
),
default: configData?.all_new_question_for_following_tags?.map(
(v) => v.enable,
),
enumNames: configData?.all_new_question_for_following_tags?.map((v) =>
t(v.key),
),
},
},
};
const uiSchema: UISchema = {
notice_switch: {
'ui:widget': 'switch',
inbox: {
'ui:widget': 'checkbox',
'ui:options': {
label: t('email.radio'),
label: t('email'),
},
},
all_new_question: {
'ui:widget': 'checkbox',
'ui:options': {
label: t('email'),
},
},
all_new_question_for_following_tags: {
'ui:widget': 'checkbox',
'ui:options': {
label: t('email'),
text: t('all_new_question_for_following_tags.description'),
},
},
};
const [formData, setFormData] = useState<FormDataType>(initFormData(schema));
const getProfile = () => {
getLoggedUserInfo().then((res) => {
if (res) {
setFormData({
notice_switch: {
value: res.notice_status === 1,
isInvalid: false,
errorMsg: '',
},
});
}
});
};
useEffect(() => {
setFormData(initFormData(schema));
}, [configData]);
const handleSubmit = (event: FormEvent) => {
event.preventDefault();
event.stopPropagation();
setNotice({
notice_switch: formData.notice_switch.value,
}).then(() => {
const params = {
inbox: configData?.inbox.map((v, index) => {
return { enable: formData.inbox.value[index], key: v.key };
}),
all_new_question: configData?.all_new_question.map((v, index) => {
return { enable: formData.all_new_question.value[index], key: v.key };
}),
all_new_question_for_following_tags:
configData?.all_new_question_for_following_tags.map((v, index) => {
return {
enable: formData.all_new_question_for_following_tags.value[index],
key: v.key,
};
}),
} as NotificationConfig;
putNotificationConfig(params).then(() => {
toast.onShow({
msg: t('update', { keyPrefix: 'toast' }),
variant: 'success',
@ -58,9 +102,6 @@ const Index = () => {
});
};
useEffect(() => {
getProfile();
}, []);
const handleChange = (ud) => {
setFormData(ud);
};

View File

@ -1,3 +1,5 @@
import useSWR from 'swr';
import request from '@/utils/request';
import type * as Type from '@/common/interface';
@ -14,3 +16,14 @@ export const updateUserInterface = (lang: string) => {
language: lang,
});
};
export const useGetNotificationConfig = () => {
return useSWR<Type.NotificationConfig>(
'/answer/api/v1/user/notification/config',
request.instance.get,
);
};
export const putNotificationConfig = (data: Type.NotificationConfig) => {
return request.put('/answer/api/v1/user/notification/config', data);
};