This commit is contained in:
Alex Holliday committed 2025-12-12 14:56:54 -08:00
1 parent 5e9c85f372
commit 92f7a929fa
6 files changed
+626 -576

No files matched your search

+2 -1
View File
@@ -2,5 +2,6 @@ window.__ENV = {
GLOBAL_REFRESH: "60000",
APP_HOST: "http://localhost:5173",
APP_API_BASE_URL: "http://localhost:52345/api/v1",
APP_DEPLOYMENT_MODE: "self_hosted",
// APP_DEPLOYMENT_MODE: "self_hosted",
APP_DEPLOYMENT_MODE: "saas",
};
@@ -34,7 +34,7 @@ export const HeaderCreate = ({
gap={theme.spacing(6)}
>
<Tooltip
title={limitReached ? "Upgrade your plan to create more teams" : ""}
title={limitReached ? t("common.tooltips.limitReached") : ""}
disableHoverListener={!limitReached}
>
<span>
@@ -46,7 +46,7 @@ export const HeaderCreate = ({
onClick={() => navigate(path)}
>
{limitReached
? "Your plan's limit has been reached"
? t("common.buttons.limitReached")
: label || t("common.buttons.createNew")}
</Button>
</span>
@@ -3,29 +3,14 @@ import Typography from "@mui/material/Typography";
import { Link, useLocation } from "react-router-dom";
import { useTheme } from "@mui/material/styles";
import { ChevronRight, Home } from "lucide-react";
const pathNameMap: Record<string, string> = {
uptime: "Uptime Monitors",
pagespeed: "PageSpeed Monitors",
infrastructure: "Infrastructure Monitors",
diagnostics: "Diagnostics",
incidents: "Incidents",
maintenance: "Maintenance",
"notification-channels": "Notification Channels",
"status-pages": "Status Pages",
teams: "Teams",
settings: "Settings",
create: "Create",
configure: "Configure",
invite: "Invite",
"team-members": "Team Members",
};
import { useTranslation } from "react-i18next";
export const Breadcrumb = ({
breadcrumbOverride,
}: {
breadcrumbOverride?: string[];
}) => {
const { t } = useTranslation();
const theme = useTheme();
const location = useLocation();
@@ -81,7 +66,8 @@ export const Breadcrumb = ({
const to = `/${pathnames.slice(0, index + 1).join("/")}`;
let displayName =
pathNameMap[value] || value.charAt(0).toUpperCase() + value.slice(1);
t(`common.breadcrumbs.${value}`) ||
value.charAt(0).toUpperCase() + value.slice(1);
// Paths that are IDs should be detail pages
if (value.length === 24 || value.match(/^[a-f0-9-]{36}$/)) {
@@ -15,6 +15,7 @@ import Tooltip from "@mui/material/Tooltip";
import { useTheme } from "@mui/material/styles";
import type { Entitlements, PlanKey } from "@/types/entitlements";
import { useTranslation } from "react-i18next";
export const PlanCard = ({
plan,
@@ -27,6 +28,7 @@ export const PlanCard = ({
onClick?: (planKey: PlanKey) => void;
loading?: boolean;
}) => {
const { t } = useTranslation();
const selected = plan.plan === currentPlan;
const theme = useTheme();
const checkColor =
@@ -60,34 +62,34 @@ export const PlanCard = ({
})();
const featureItems = [
{
label: "Monitors",
label: t("billing.plans.features.monitors.title"),
value: plan.monitorsMax,
tooltip: "Maximum number of monitors allowed.",
tooltip: t("billing.plans.features.monitors.toolTip"),
},
{
label: "Status pages",
label: t("billing.plans.features.statusPages.title"),
value: plan.statusPagesMax,
tooltip: "Maximum public status pages you can create.",
tooltip: t("billing.plans.features.statusPages.toolTip"),
},
{
label: "Notification channels",
label: t("billing.plans.features.notificationChannels.title"),
value: plan.notificationChannelsMax,
tooltip: "Maximum alerting channels (email, Slack, etc.).",
tooltip: t("billing.plans.features.notificationChannels.toolTip"),
},
{
label: "Teams",
label: t("billing.plans.features.teams.title"),
value: plan.teamsMax,
tooltip: "Maximum number of teams in your org.",
tooltip: t("billing.plans.features.teams.toolTip"),
},
{
label: "Retention",
label: t("billing.plans.features.retention.title"),
value: `${plan.retentionDays} days`,
tooltip: "Oldest checks are automatically removed after retention.",
tooltip: t("billing.plans.features.retention.toolTip"),
},
{
label: "Min interval",
label: t("billing.plans.features.interval.title"),
value: `${Math.round(plan.checksIntervalMsMin / 1000)}s`,
tooltip: "Minimum check frequency allowed for this plan.",
tooltip: t("billing.plans.features.interval.toolTip"),
},
];
return (
@@ -128,7 +130,7 @@ export const PlanCard = ({
{plan.plan === "pro" && (
<Chip
size="small"
label="Most popular"
label={t("billing.plans.mostPopular")}
sx={{
bgcolor: theme.palette.primary.main,
color: theme.palette.getContrastText(
@@ -150,12 +152,20 @@ export const PlanCard = ({
<Check size={16} color={checkColor} />
{item.tooltip ? (
<Tooltip title={item.tooltip} arrow placement="right">
<Typography variant="body1" color="text.secondary" fontSize={18}>
<Typography
variant="body1"
color="text.secondary"
fontSize={18}
>
{item.label}: {item.value}
</Typography>
</Tooltip>
) : (
<Typography variant="body1" color="text.secondary" fontSize={18}>
<Typography
variant="body1"
color="text.secondary"
fontSize={18}
>
{item.label}: {item.value}
</Typography>
)}
+588 -537
View File
File diff suppressed because it is too large. Load diff
+5 -3
View File
@@ -3,6 +3,7 @@ import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import { Button } from "@/components/inputs";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "@/hooks/AppHooks";
import { useGet, usePost } from "@/hooks/UseApi";
import type { ApiResponse } from "@/hooks/UseApi";
@@ -12,6 +13,7 @@ import type { IUser } from "@/types/user";
import { setSelectedTeamId, setUser } from "@/features/authSlice";
const BillingPage = () => {
const { t } = useTranslation();
const { user } = useAppSelector((state) => state.auth);
const { response } = useGet<ApiResponse<Entitlements[]>>(
"/billing/plans",
@@ -62,8 +64,8 @@ const BillingPage = () => {
return (
<BasePage>
<InfoBox
title="Choose a plan!"
description="Choose a plan that fits your needs and start enjoying our services."
title={t("billing.infoBox.title")}
description={t("billing.infoBox.description")}
/>
<Grid container spacing={10} columns={{ xs: 1, sm: 2, md: 4 }}>
{plans.map((plan) => (
@@ -85,7 +87,7 @@ const BillingPage = () => {
onClick={handleCancel}
loading={isPosting}
>
Cancel subscription
{t("buttons.cancelSubscription")}
</Button>
</Box>
)}