Strip ProChip badges, ProDialog upsell modals, and pro-conditional click interception across admin settings, group editing, storage policy selection, custom props, email templates, audit events, and navigation. Feature UI now renders and is reachable without a license. Also fixes a latent upstream ReferenceError: PageNavigation used undeclared proOpen/setProOpen state, which would crash on click of any Pro-gated nav item. "Open user files" in the user dialog now navigates to the admin file list filtered by owner instead of opening an upsell dialog. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>pull/3579/head
parent
88b1910d99
commit
ed2dd60263
@ -1,141 +0,0 @@
|
|||||||
import {
|
|
||||||
Alert,
|
|
||||||
AlertTitle,
|
|
||||||
Button,
|
|
||||||
DialogContent,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemIcon,
|
|
||||||
ListItemText,
|
|
||||||
Typography,
|
|
||||||
styled,
|
|
||||||
} from "@mui/material";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { useCallback, useMemo } from "react";
|
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
|
||||||
import DraggableDialog, { StyledDialogActions } from "../../Dialogs/DraggableDialog";
|
|
||||||
import CheckmarkCircleFilled from "../../Icons/CheckmarkCircleFilled";
|
|
||||||
import Gift from "../../Icons/Gift";
|
|
||||||
import { Code } from "../../Common/Code.tsx";
|
|
||||||
|
|
||||||
export interface ProDialogProps {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const features = [
|
|
||||||
"shareLinkCollabration",
|
|
||||||
"filePermission",
|
|
||||||
"multipleStoragePolicy",
|
|
||||||
"auditAndActivity",
|
|
||||||
"vasService",
|
|
||||||
"sso",
|
|
||||||
"more",
|
|
||||||
];
|
|
||||||
|
|
||||||
const StyledButton = styled(Button)(({ theme }) => ({
|
|
||||||
background: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.primary.light} 90%)`,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
"&:hover": {
|
|
||||||
background: `linear-gradient(45deg, ${theme.palette.primary.dark} 30%, ${theme.palette.primary.main} 90%)`,
|
|
||||||
},
|
|
||||||
transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1) !important",
|
|
||||||
}));
|
|
||||||
|
|
||||||
// TODO: fetch from cloudreve.org
|
|
||||||
const currentPromotion = {
|
|
||||||
code: "LX8YL9QP0",
|
|
||||||
discount: 15,
|
|
||||||
start: "2026-03-14T02:00:00Z",
|
|
||||||
end: "2026-06-14T02:00:00Z",
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProDialog = ({ open, onClose }: ProDialogProps) => {
|
|
||||||
const { t } = useTranslation("dashboard");
|
|
||||||
const openMore = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
window.open("https://cloudreve.org/pro", "_blank");
|
|
||||||
}, []);
|
|
||||||
const showPromotion = useMemo(() => {
|
|
||||||
const now = dayjs();
|
|
||||||
return now >= dayjs(currentPromotion.start) && now <= dayjs(currentPromotion.end);
|
|
||||||
}, []);
|
|
||||||
return (
|
|
||||||
<DraggableDialog
|
|
||||||
title={t("pro.title")}
|
|
||||||
dialogProps={{
|
|
||||||
open,
|
|
||||||
onClose,
|
|
||||||
maxWidth: "sm",
|
|
||||||
fullWidth: true,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DialogContent>
|
|
||||||
<Typography variant="body1" color="text.secondary">
|
|
||||||
{t("pro.description")}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Typography variant="body1" fontWeight={600} sx={{ mt: 2 }}>
|
|
||||||
{t("pro.proInclude")}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<List dense>
|
|
||||||
{features.map((feature) => (
|
|
||||||
<ListItem key={feature}>
|
|
||||||
<ListItemIcon
|
|
||||||
sx={{
|
|
||||||
minWidth: "36px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CheckmarkCircleFilled color="primary" />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText
|
|
||||||
slotProps={{
|
|
||||||
primary: {
|
|
||||||
sx: {},
|
|
||||||
variant: "body1",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t(`pro.${feature}`)}
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
{showPromotion && (
|
|
||||||
<Alert
|
|
||||||
iconMapping={{
|
|
||||||
info: <Gift fontSize="inherit" />,
|
|
||||||
}}
|
|
||||||
severity="info"
|
|
||||||
sx={{ mt: 2 }}
|
|
||||||
>
|
|
||||||
<AlertTitle>{t("pro.promotionTitle")}</AlertTitle>
|
|
||||||
<Trans
|
|
||||||
i18nKey="dashboard:pro.promotion"
|
|
||||||
values={{
|
|
||||||
code: currentPromotion.code,
|
|
||||||
discount: currentPromotion.discount,
|
|
||||||
}}
|
|
||||||
components={[<Code />, <Typography component={"span"} fontWeight={600} />]}
|
|
||||||
/>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
</DialogContent>
|
|
||||||
<StyledDialogActions
|
|
||||||
sx={{
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button variant="outlined" color="primary" onClick={onClose}>
|
|
||||||
{t("pro.later")}
|
|
||||||
</Button>
|
|
||||||
<StyledButton onClick={openMore} variant="contained" color="primary">
|
|
||||||
{t("pro.learnMore")}
|
|
||||||
</StyledButton>
|
|
||||||
</StyledDialogActions>
|
|
||||||
</DraggableDialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProDialog;
|
|
||||||
Loading…
Reference in new issue