743 lines
22 KiB
TypeScript
743 lines
22 KiB
TypeScript
'use client'
|
|
|
|
import { type MDXRemoteSerializeResult } from "next-mdx-remote";
|
|
import { serialize } from "next-mdx-remote/serialize";
|
|
import { MDXRemote } from 'next-mdx-remote/rsc'
|
|
// import { promises as fs } from "fs";
|
|
import { MdxContent } from "../../../components/mdx-content";
|
|
// import { Web3Provider } from "@/components/providers/web3-provider";
|
|
import { Header, NavBack } from "@/components/header";
|
|
import { Footer } from "@/components/footer";
|
|
import { Button, Checkbox, Form, GetProp, Input, Radio, RadioChangeEvent, Space } from "antd";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import service from "@/lib/http/service";
|
|
import toast from 'react-hot-toast';
|
|
import { UserData } from "@/components/user-menu";
|
|
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
|
|
import { useTranslation } from "react-i18next";
|
|
import Link from "next/link";
|
|
import { useSearchParams } from "next/navigation";
|
|
import { LoadingView } from "@/components/ui/loading";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
|
|
type Frontmatter = {
|
|
title: string;
|
|
date: string;
|
|
};
|
|
|
|
type Post<TFrontmatter> = {
|
|
serialized: MDXRemoteSerializeResult;
|
|
frontmatter: TFrontmatter;
|
|
};
|
|
|
|
// export const runtime = "nodejs";
|
|
export const runtime = "edge";
|
|
|
|
interface ExtraData {
|
|
logs: any; // 此处的类型需根据实际数据类型确定
|
|
}
|
|
|
|
export interface Info {
|
|
email: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
title: string;
|
|
company: string;
|
|
tags: string[];
|
|
}
|
|
|
|
export interface TagInfo {
|
|
id: number;
|
|
name: string;
|
|
name_cn: string;
|
|
is_inherent: boolean; //是否内置 不可操作
|
|
is_deleted: boolean; //
|
|
checked: boolean; //
|
|
created_time: string;
|
|
updated_time: string;
|
|
label?: string;
|
|
extra_data: ExtraData;
|
|
|
|
}
|
|
|
|
type CheckboxValueType = GetProp<typeof Checkbox.Group, 'value'>[number];
|
|
|
|
export default function PostsPage() {
|
|
// Get the serialized content and frontmatter
|
|
|
|
const infoRef = useRef<Info>({
|
|
email: "",
|
|
first_name: "",
|
|
last_name: "",
|
|
title: "",
|
|
company: "",
|
|
tags: [],
|
|
|
|
});
|
|
|
|
const [form] = Form.useForm();
|
|
const [clientReady, setClientReady] = useState<boolean>(false);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
|
|
const [initLoading, setInitLoading] = useState<boolean>(true);
|
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
|
const [isOther, setIsOther] = useState(false);
|
|
const [tagsRef, setTagsRef] = useState<TagInfo[]>([]);
|
|
const [tagsRefList, setTagsRefList] = useState<string[]>([]);
|
|
const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([]);
|
|
|
|
const [checked, setChecked] = useState(true);
|
|
|
|
const { t, i18n } = useTranslation()
|
|
|
|
const language = i18n.language
|
|
|
|
const [userData, setUserData] = useLocalStorage(
|
|
'UserData',
|
|
{
|
|
auth_token: "",
|
|
id: 1,
|
|
login_ip: "",
|
|
login_time: 0,
|
|
role: "",
|
|
user_name: "",
|
|
version: ""
|
|
} as UserData
|
|
)
|
|
|
|
const searchParams = useSearchParams()
|
|
const email = searchParams.get('email')
|
|
if (!!email) {
|
|
infoRef.current.email = email
|
|
}
|
|
if (!!userData.auth_token) {
|
|
infoRef.current.email = userData.user_name
|
|
}
|
|
// let first_name = ""
|
|
// let last_name = ""
|
|
// let title = ""
|
|
// let company = ""
|
|
// let tags = [] as string[]
|
|
|
|
// console.log("email", email, userData.auth_token)
|
|
|
|
// To disable submit button at the beginning.
|
|
useEffect(() => {
|
|
|
|
// console.log("------------email", infoRef.current, userData.auth_token)
|
|
if (!!infoRef.current.email) {
|
|
|
|
setIsLoadingInfo(true);
|
|
async function initFunc() {
|
|
await service.post('/api/v1/customer/sub-info', {
|
|
email: infoRef.current.email
|
|
}, {
|
|
headers: {
|
|
// 'Authorization': token
|
|
}
|
|
}).then(function (result: any) {
|
|
|
|
|
|
console.log("result:", result)
|
|
|
|
if (result && result.header.code != 0) {
|
|
|
|
toast.error(result.header.message)
|
|
return
|
|
}
|
|
|
|
// categoriesRef.current.values
|
|
|
|
|
|
infoRef.current.first_name = result.data.first_name
|
|
infoRef.current.last_name = result.data.last_name
|
|
infoRef.current.title = result.data.title
|
|
infoRef.current.company = result.data.company
|
|
infoRef.current.tags = result.data.tags
|
|
|
|
setIsLoadingInfo(false);
|
|
|
|
}).catch((err) => {
|
|
console.log(err);
|
|
|
|
});
|
|
}
|
|
|
|
initFunc()
|
|
}
|
|
setClientReady(true);
|
|
|
|
|
|
}, [userData]);
|
|
|
|
useEffect(() => {
|
|
let isMounted = true
|
|
|
|
setInitLoading(true);
|
|
async function initFunc() {
|
|
await service.post('/api/v1/tag/list', {
|
|
}, {
|
|
headers: {
|
|
// 'Authorization': token
|
|
}
|
|
}).then(function (result: any) {
|
|
|
|
|
|
console.log("result:", result)
|
|
|
|
if (result && result.header.code != 0) {
|
|
|
|
toast.error(result.header.message)
|
|
return
|
|
}
|
|
|
|
// categoriesRef.current.values
|
|
|
|
|
|
const tags = result.data.list
|
|
// setCheckedList(tags.map((i: TagInfo) => i.name))
|
|
infoRef.current.tags = tags.map((i: TagInfo) => i.name)
|
|
|
|
setTagsRef(tags.map((r: TagInfo) => {
|
|
return {
|
|
...r,
|
|
checked: true
|
|
}
|
|
|
|
}))
|
|
|
|
setTimeout(() => {
|
|
console.log('-----checkedList--------', tags.map((r: TagInfo) => {
|
|
return {
|
|
...r,
|
|
checked: true
|
|
}
|
|
|
|
}))
|
|
setInitLoading(false);
|
|
}, 1000);
|
|
|
|
|
|
// form.setFieldValue('email', email);
|
|
|
|
}).catch((err) => {
|
|
setInitLoading(false);
|
|
console.log(err);
|
|
|
|
});
|
|
}
|
|
|
|
initFunc()
|
|
|
|
return () => {
|
|
isMounted = false
|
|
}
|
|
}, [])
|
|
|
|
|
|
|
|
const [value, setValue] = useState(1);
|
|
|
|
const onChange = (e: RadioChangeEvent) => {
|
|
console.log('radio checked', e.target.value);
|
|
|
|
if (e.target.value == "Other") {
|
|
setIsOther(true)
|
|
|
|
} else {
|
|
setIsOther(false)
|
|
}
|
|
|
|
setValue(e.target.value);
|
|
|
|
};
|
|
|
|
const onFinish = async (values: any) => {
|
|
console.log('Finish:', values);
|
|
|
|
|
|
const token = userData.auth_token
|
|
// if (!token) {
|
|
// router.push('/auth/sign-in')
|
|
// return
|
|
// }
|
|
// /api/v1/customer/subscribe
|
|
if (isLoading) return
|
|
|
|
setIsLoading(true);
|
|
let result: any = await service.post('/api/v1/customer/edit', {
|
|
language,
|
|
"first_name": values.first_name,
|
|
"last_name": values.last_name,
|
|
"title": values.title,
|
|
"company": values.company,
|
|
"email": values.email,
|
|
}, {
|
|
headers: {
|
|
'Authorization': token
|
|
}
|
|
})
|
|
|
|
setIsLoading(false);
|
|
console.log("result:", result)
|
|
|
|
if (result && result.header.code != 0) {
|
|
|
|
toast.error(result.header.message)
|
|
return
|
|
}
|
|
|
|
if (!values.unall) {
|
|
|
|
// let tags: string[] = []
|
|
// if (values.remember) {
|
|
// tags.push("#Blockchain")
|
|
// }
|
|
|
|
// if (values.remember2) {
|
|
// tags.push("#AI")
|
|
// }
|
|
|
|
console.log("values.first_name", values.first_name)
|
|
// setIsLoading(true);
|
|
let result2: any = await service.post('/api/v1/customer/subscribe', {
|
|
language,
|
|
"first_name": values.first_name,
|
|
"email": values.email,
|
|
"tags": values.tags || []
|
|
}, {
|
|
headers: {
|
|
'Authorization': token
|
|
}
|
|
})
|
|
|
|
setIsLoading(false);
|
|
console.log("result:", result2)
|
|
|
|
if (result2 && result2.header.code != 0) {
|
|
|
|
toast.error(result2.header.message)
|
|
return
|
|
}
|
|
|
|
} else {
|
|
|
|
let reason = values.why
|
|
if (values.why == "Other") {
|
|
reason = values.whyOther
|
|
|
|
}
|
|
setIsLoading(true);
|
|
let result3: any = await service.post('/api/v1/customer/unsubscribe', {
|
|
language,
|
|
"email": values.email,
|
|
"reason": reason
|
|
}, {
|
|
headers: {
|
|
'Authorization': token
|
|
}
|
|
})
|
|
|
|
setIsLoading(false);
|
|
console.log("result:", result3)
|
|
|
|
if (result3 && result3.header.code != 0) {
|
|
|
|
toast.error(result3.header.message)
|
|
return
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toast.success("OK")
|
|
|
|
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* <nav className="fixed top-[4.25rem] container flex items-center justify-between " >
|
|
<Link href="/">
|
|
{t("home")}
|
|
</Link>
|
|
</nav> */}
|
|
<NavBack />
|
|
{
|
|
!initLoading && !isLoadingInfo ?
|
|
<div
|
|
|
|
className={cn(
|
|
" max-w-[1440px] mb-40 md:mb-60 mx-auto lg:px-20 lg:flex justify-between ",
|
|
// messages.length > 1 ? 'fixed bottom-0 bg-[#f6f6f6] z-[999]' : "absolute bg-[#fff]"
|
|
)}
|
|
|
|
>
|
|
<div className=" lg:pt-3 px-[1rem] lg:px-[1rem] lg:pl-20 items-start" >
|
|
|
|
<h3 className="text-[#385AFF] font-bold text-[1.5rem] lg:text-[2rem] leading-[8rem] min-w-80">{t("subscribe.manage_subscription")}</h3>
|
|
<h5 className="hidden lg:block text-[#000] text-[1.5rem] mb-[2.5rem] font-bold leading-[6rem] min-w-80">{t("subscribe.your_profile")}</h5>
|
|
<h5 className="hidden lg:block text-[#000] text-[1.5rem] font-bold leading-[6rem] min-w-80">{t("subscribe.expert_news")} </h5>
|
|
<p className="hidden lg:block text-[#000] text-[0.8rem] leading-[1.2rem] w-80">{t("subscribe.subscription_text")}</p>
|
|
</div>
|
|
|
|
<div className=" lg:pt-[11rem] px-[1rem] lg:px-[1rem]">
|
|
|
|
<Form
|
|
name="complex-form"
|
|
size="large"
|
|
layout="vertical"
|
|
autoComplete="off"
|
|
onFinish={onFinish}
|
|
// labelCol={{ span: 8 }}
|
|
// wrapperCol={{ span: 16 }}
|
|
// style={{
|
|
// width: 750
|
|
// }}
|
|
|
|
initialValues={{
|
|
email: infoRef.current.email,
|
|
first_name: infoRef.current.first_name,
|
|
last_name: infoRef.current.last_name,
|
|
title: infoRef.current.title,
|
|
company: infoRef.current.company,
|
|
tags: infoRef.current.tags,
|
|
|
|
}}
|
|
className="lg:w-[46.875rem]"
|
|
>
|
|
|
|
<div className="flex gap-[1rem] lg:gap-[0rem] items-center justify-between" style={{ marginBottom: 0 }}>
|
|
<Form.Item
|
|
name="first_name"
|
|
rules={[{ required: true }]}
|
|
>
|
|
<Input
|
|
variant="borderless"
|
|
className="placeholder:text-[#808080] lg:w-[22.5rem]"
|
|
style={{
|
|
background: "#F5F5F5",
|
|
borderRadius: "0",
|
|
// width: 360
|
|
|
|
}}
|
|
placeholder={t("subscribe.first_name")}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="last_name"
|
|
rules={[{ required: false }]}
|
|
>
|
|
<Input
|
|
variant="borderless"
|
|
className="placeholder:text-[#808080] lg:w-[22.5rem]"
|
|
style={{
|
|
background: "#F5F5F5",
|
|
borderRadius: "0",
|
|
// width: 360
|
|
|
|
}}
|
|
placeholder={t("subscribe.last_name")}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
<div className="flex gap-[1rem] lg:gap-[0rem] items-center justify-between" style={{ marginBottom: 0 }}>
|
|
<Form.Item
|
|
name="title"
|
|
rules={[{ required: false }]}
|
|
>
|
|
<Input
|
|
variant="borderless"
|
|
className="placeholder:text-[#808080] lg:w-[22.5rem]"
|
|
style={{
|
|
background: "#F5F5F5",
|
|
borderRadius: "0",
|
|
// width: 360
|
|
|
|
}}
|
|
placeholder={t("subscribe.title")}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="company"
|
|
rules={[{ required: false }]}
|
|
>
|
|
<Input
|
|
variant="borderless"
|
|
className="placeholder:text-[#808080] lg:w-[22.5rem]"
|
|
style={{
|
|
background: "#F5F5F5",
|
|
borderRadius: "0",
|
|
// width: 360
|
|
|
|
}}
|
|
placeholder={t("subscribe.company")}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
|
|
<div
|
|
className="w-full"
|
|
>
|
|
|
|
<Form.Item
|
|
name="email"
|
|
rules={[{ required: true }]}
|
|
className="w-full"
|
|
>
|
|
|
|
<Input
|
|
variant="borderless"
|
|
className="placeholder:text-[#808080]"
|
|
// defaultValue={email ? email : undefined}
|
|
|
|
style={{
|
|
background: "#F5F5F5",
|
|
borderRadius: "0",
|
|
// width: 360
|
|
|
|
}}
|
|
placeholder={t("subscribe.business_email_address")}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
|
|
<div className="flex flex-row lg:flex-row items-center justify-between transition duration-500" style={{ marginBottom: 0 }}>
|
|
|
|
<Form.Item
|
|
|
|
name="tags"
|
|
// name={item.name}
|
|
// valuePropName={item.name}
|
|
// wrapperCol={{ offset: 8, span: 16 }}
|
|
style={{
|
|
minWidth: "100px"
|
|
}}
|
|
|
|
|
|
|
|
>
|
|
{/* <Checkbox onChange={(e) => {
|
|
console.log('checked = ', e.target.checked);
|
|
tagsRef[index].checked = e.target.checked
|
|
}} checked={item.checked} className="w-full whitespace-nowrap" >{language == 'en' ? item.name : item.name_cn}</Checkbox> */}
|
|
|
|
|
|
{/* <Checkbox.Group style={{ width: '80%' }} value={checkedList} onChange={onChangeCheck} >
|
|
<Row>
|
|
{options.map((r, i) => {
|
|
return <Col key={r.label} span={4}>
|
|
<Checkbox disabled={is_inherent ? true : false} className="gutter-row" value={r.value}>{r.label}</Checkbox>
|
|
</Col>
|
|
})}
|
|
</Row>
|
|
</Checkbox.Group>
|
|
*/}
|
|
{!initLoading && !isSubscribe && <Checkbox.Group
|
|
className="tags grid grid-cols-1 gap-8 lg:grid-cols-2 "
|
|
options={tagsRef.map(i => i.name)}
|
|
// value={checkedList}
|
|
value={checkedList}
|
|
onChange={(list) => {
|
|
console.log('----Checkbox.Group------', list)
|
|
setCheckedList(list)
|
|
}}
|
|
>
|
|
{/* {
|
|
tagsRef.map((item, index) => {
|
|
return <Checkbox
|
|
key={index}
|
|
className="w-[22.5rem] h-[9rem] flex items-center justify-center rounded border border-[#243c5a]"
|
|
value={item.name}
|
|
// checked={!!userData.auth_token ? item.checked : true}
|
|
checked={true}
|
|
onChange={(e: any) => {
|
|
console.log('checked = ', e);
|
|
// setCheckedList(list);
|
|
// tagsRef[index].checked = e.target.checked
|
|
setTagsRef(tagsRef.map((r: TagInfo, i: number) => {
|
|
if (index = i) {
|
|
return {
|
|
...r,
|
|
checked: e.target.checked
|
|
}
|
|
}
|
|
return r
|
|
|
|
}))
|
|
|
|
}}>{language == 'en' ? item.name : item.name_cn}</Checkbox>
|
|
})
|
|
} */}
|
|
|
|
</Checkbox.Group>}
|
|
</Form.Item>
|
|
|
|
|
|
{/* <Form.Item
|
|
name="remember"
|
|
valuePropName="checked"
|
|
wrapperCol={{ offset: 8, span: 16 }}
|
|
style={{
|
|
minWidth: "100px"
|
|
}}
|
|
|
|
className="w-[22.5rem] h-[9rem] flex items-center justify-center rounded border border-[#243c5a]"
|
|
|
|
>
|
|
<Checkbox className="w-full whitespace-nowrap" >{t("subscribe.cryptocurrency")}</Checkbox>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="remember2"
|
|
// valuePropName="checked2"
|
|
valuePropName="checked"
|
|
wrapperCol={{ offset: 8, span: 16 }}
|
|
style={{
|
|
minWidth: "100px"
|
|
}}
|
|
|
|
className="w-[22.5rem] h-[9rem] flex items-center justify-center rounded border border-[#243c5a]"
|
|
|
|
>
|
|
<Checkbox className="w-full whitespace-nowrap">{t("subscribe.ai")}</Checkbox>
|
|
</Form.Item> */}
|
|
</div>
|
|
|
|
|
|
|
|
<div className="ml-[0px] " style={{ marginBottom: 0 }}>
|
|
|
|
<Form.Item
|
|
name="unall"
|
|
// valuePropName="checked3"
|
|
valuePropName="checked"
|
|
// wrapperCol={{ offset: 8, span: 16 }}
|
|
style={{
|
|
// minWidth: "100px"
|
|
}}
|
|
|
|
className=" h-[1rem]] lg:min-w-[6.25rem]"
|
|
|
|
>
|
|
<Checkbox className="w-full text-[1.125rem] " onChange={(e) => {
|
|
console.log(e.target.checked)
|
|
|
|
setIsSubscribe(e.target.checked)
|
|
}}>{t("subscribe.unsubscribe_from_all")}</Checkbox>
|
|
</Form.Item>
|
|
</div>
|
|
|
|
{isSubscribe && <div className="block rounded border-[#243c5a] bg-[#F5F5F5] text-[#808080] transition duration-500 py-[0.5rem]" style={{ marginBottom: 0 }}>
|
|
<h5 className="ml-[30px] leading-[3rem] font-bold text-[#3D3D3D]">{t("subscribe.tell_us_why")}</h5>
|
|
<Form.Item
|
|
className="block h-[1rem]] mb-[0] min-w-[3.25rem] lg:min-w-[6.25rem]"
|
|
name="why"
|
|
// valuePropName="checked"
|
|
// label="Radio.Group"
|
|
wrapperCol={{
|
|
offset: 1,
|
|
// span: 16
|
|
}}
|
|
style={{
|
|
// minWidth: "100px"
|
|
}}
|
|
|
|
|
|
>
|
|
<Radio.Group onChange={onChange} value={value}>
|
|
<Space direction="vertical" >
|
|
{
|
|
[
|
|
t("subscribe.reason1"),
|
|
t("subscribe.reason2"),
|
|
t("subscribe.reason3"),
|
|
t("subscribe.reason4"),
|
|
// "Other",
|
|
].map((arg, i) => {
|
|
return <Radio key={i} value={arg} className="text-[#808080] leading-[1.4rem]">{arg}</Radio>
|
|
})
|
|
}
|
|
|
|
|
|
|
|
<Radio value="Other" className="text-[#808080] leading-[1.4rem]">{t("subscribe.reason5")}</Radio>
|
|
</Space>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
|
|
|
|
{isOther && <div className="pt-[0.6rem] w-[88%] lg:w-auto">
|
|
<Form.Item label=""
|
|
name="whyOther"
|
|
wrapperCol={{
|
|
offset: 2,
|
|
span: 16
|
|
}}
|
|
// validateStatus="error"
|
|
// hasFeedback
|
|
// help="Should have something"
|
|
>
|
|
<Input.TextArea
|
|
allowClear
|
|
// showCount
|
|
style={{
|
|
background: "#fff",
|
|
borderRadius: "0",
|
|
border: "none",
|
|
height: "100px",
|
|
}}
|
|
className=""
|
|
/>
|
|
</Form.Item>
|
|
</div>}
|
|
|
|
|
|
</div>}
|
|
|
|
|
|
|
|
|
|
<Form.Item shouldUpdate className="my-[1rem]">
|
|
{() => (
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
className='bg-[#1A1A1A] hover:bg-[#385AFF] active:bg-[#385AFF] disabled:[#424b77]'
|
|
disabled={
|
|
!clientReady
|
|
// ||
|
|
// !form.isFieldsTouched(true) ||
|
|
// !!form.getFieldsError().filter(({ errors }) => errors.length).length
|
|
}
|
|
style={{
|
|
// background: "#1A1A1A",
|
|
borderRadius: "0",
|
|
// width: 116,
|
|
color: "#fff",
|
|
// backgroundColor: '#808080', // 设置悬停时的背景颜色
|
|
// borderColor: '#808080', // 设置边框颜色,可根据需要调整
|
|
|
|
}}
|
|
>
|
|
{t("subscribe.update_subscriptions")}
|
|
</Button>
|
|
)}
|
|
</Form.Item>
|
|
</Form>
|
|
</div>
|
|
|
|
|
|
</div> : <LoadingView />}
|
|
{/* <Footer /> */}
|
|
</ >
|
|
);
|
|
|
|
|
|
}
|