cherry-studio/src/renderer/src/components/Popups/PrivacyPopup.tsx
kangfenmao cc650b58d3 feat(privacy): add English and Chinese privacy policy pages and popup component
- Introduced new HTML files for the privacy policy in English and Chinese.
- Implemented a PrivacyPopup component to display the privacy policy within the application.
- The popup dynamically loads the appropriate language based on user settings and includes options to accept or decline the policy.
2025-09-23 19:49:41 +08:00

138 lines
3.5 KiB
TypeScript

import { TopView } from '@renderer/components/TopView'
import { useTheme } from '@renderer/context/ThemeProvider'
import { ThemeMode } from '@renderer/types'
import { runAsyncFunction } from '@renderer/utils'
import { Button, Modal } from 'antd'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
const WebViewContainer = styled.div`
width: 100%;
height: 500px;
overflow: hidden;
webview {
width: 100%;
height: 100%;
border: none;
background: transparent;
}
`
interface ShowParams {
title?: string
showDeclineButton?: boolean
}
interface Props extends ShowParams {
resolve: (data: any) => void
}
const PopupContainer: React.FC<Props> = ({ title, showDeclineButton = true, resolve }) => {
const [open, setOpen] = useState(true)
const [privacyUrl, setPrivacyUrl] = useState<string>('')
const { theme } = useTheme()
const { i18n } = useTranslation()
const getTitle = () => {
if (title) return title
const isChinese = i18n.language.startsWith('zh')
return isChinese ? '隐私协议' : 'Privacy Policy'
}
const handleAccept = () => {
setOpen(false)
localStorage.setItem('privacy-popup-accepted', 'true')
resolve({ accepted: true })
}
const handleDecline = () => {
setOpen(false)
window.api.quit()
resolve({ accepted: false })
}
const onClose = () => {
if (!showDeclineButton) {
handleAccept()
} else {
handleDecline()
}
}
useEffect(() => {
runAsyncFunction(async () => {
const { appPath } = await window.api.getAppInfo()
const isChinese = i18n.language.startsWith('zh')
const htmlFile = isChinese ? 'privacy-zh.html' : 'privacy-en.html'
const url = `file://${appPath}/resources/cherry-studio/${htmlFile}?theme=${theme === ThemeMode.dark ? 'dark' : 'light'}`
setPrivacyUrl(url)
})
}, [theme, i18n.language])
PrivacyPopup.hide = () => setOpen(false)
return (
<Modal
title={getTitle()}
open={open}
onCancel={showDeclineButton ? handleDecline : undefined}
afterClose={onClose}
transitionName=""
maskTransitionName=""
centered
closable={false}
maskClosable={false}
styles={{
mask: { backgroundColor: 'var(--color-background)' },
header: { paddingLeft: 20 },
body: { paddingLeft: 20 }
}}
width={900}
footer={[
showDeclineButton && (
<Button key="decline" onClick={handleDecline}>
{i18n.language.startsWith('zh') ? '拒绝' : 'Decline'}
</Button>
),
<Button key="accept" type="primary" onClick={handleAccept}>
{i18n.language.startsWith('zh') ? '同意并继续' : 'Accept and Continue'}
</Button>
].filter(Boolean)}>
<WebViewContainer>
{privacyUrl && <webview src={privacyUrl} style={{ width: '100%', height: '100%' }} />}
</WebViewContainer>
</Modal>
)
}
const TopViewKey = 'PrivacyPopup'
export default class PrivacyPopup {
static topviewId = 0
static hide() {
TopView.hide(TopViewKey)
}
static async show(props?: ShowParams) {
const accepted = localStorage.getItem('privacy-popup-accepted')
if (accepted) {
return
}
return new Promise<{ accepted: boolean }>((resolve) => {
TopView.show(
<PopupContainer
{...(props || {})}
resolve={(v) => {
resolve(v)
TopView.hide(TopViewKey)
}}
/>,
TopViewKey
)
})
}
}