fix colors in dashboard (#206)
This commit is contained in:
@@ -146,35 +146,35 @@ export default function CampaignDetailsPage({
|
||||
}
|
||||
|
||||
const CampaignStatusBadge: React.FC<{ status: string }> = ({ status }) => {
|
||||
let outsideColor = "bg-gray-600";
|
||||
let insideColor = "bg-gray-600/50";
|
||||
let outsideColor = "bg-gray";
|
||||
let insideColor = "bg-gray/50";
|
||||
|
||||
switch (status) {
|
||||
case "delivered":
|
||||
outsideColor = "bg-emerald-500/30";
|
||||
insideColor = "bg-emerald-500";
|
||||
outsideColor = "bg-green/30";
|
||||
insideColor = "bg-green";
|
||||
break;
|
||||
case "bounced":
|
||||
case "unsubscribed":
|
||||
outsideColor = "bg-red-500/30";
|
||||
insideColor = "bg-red-500";
|
||||
outsideColor = "bg-red/30";
|
||||
insideColor = "bg-red";
|
||||
break;
|
||||
case "clicked":
|
||||
outsideColor = "bg-cyan-500/30";
|
||||
insideColor = "bg-cyan-500";
|
||||
outsideColor = "bg-blue/30";
|
||||
insideColor = "bg-blue";
|
||||
break;
|
||||
case "opened":
|
||||
outsideColor = "bg-indigo-500/30";
|
||||
insideColor = "bg-indigo-500";
|
||||
outsideColor = "bg-purple/30";
|
||||
insideColor = "bg-purple";
|
||||
break;
|
||||
|
||||
case "complained":
|
||||
outsideColor = "bg-yellow-500/30";
|
||||
insideColor = "bg-yellow-500";
|
||||
outsideColor = "bg-yellow/30";
|
||||
insideColor = "bg-yellow";
|
||||
break;
|
||||
default:
|
||||
outsideColor = "bg-gray-600/40";
|
||||
insideColor = "bg-gray-600";
|
||||
outsideColor = "bg-gray/40";
|
||||
insideColor = "bg-gray";
|
||||
}
|
||||
|
||||
return (
|
||||
|
@@ -103,10 +103,10 @@ export default function CampaignList() {
|
||||
<div
|
||||
className={`text-center w-[130px] rounded capitalize py-1 text-xs ${
|
||||
campaign.status === CampaignStatus.DRAFT
|
||||
? "bg-gray-500/15 dark:bg-gray-400/15 text-gray-700 dark:text-gray-400/90 border border-gray-500/25 dark:border-gray-700/25"
|
||||
? "bg-gray/15 text-gray border border-gray/25"
|
||||
: campaign.status === CampaignStatus.SENT
|
||||
? "bg-green-500/15 dark:bg-green-600/10 text-green-700 dark:text-green-600/90 border border-green-500/25 dark:border-green-700/25"
|
||||
: "bg-yellow-500/15 dark:bg-yellow-600/10 text-yellow-700 dark:text-yellow-600/90 border border-yellow-500/25 dark:border-yellow-700/25"
|
||||
? "bg-green/15 text-green border border-green/25"
|
||||
: "bg-yellow/15 text-yellow border border-yellow/25"
|
||||
}`}
|
||||
>
|
||||
{campaign.status.toLowerCase()}
|
||||
|
@@ -62,7 +62,7 @@ export const DeleteCampaign: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`Campaign deleted`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export const DeleteCampaign: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="p-0 hover:bg-transparent">
|
||||
<Trash2 className="h-[18px] w-[18px] text-red-600/80" />
|
||||
<Trash2 className="h-[18px] w-[18px] text-red/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -35,7 +35,7 @@ export const DuplicateCampaign: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`Campaign duplicated`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export const DuplicateCampaign: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="p-0 hover:bg-transparent">
|
||||
<Copy className="h-[18px] w-[18px] text-blue-600/80" />
|
||||
<Copy className="h-[18px] w-[18px] text-blue/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -152,13 +152,13 @@ export default function ContactList({
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{contact.subscribed ? (
|
||||
<div className="text-center w-[130px] rounded capitalize py-1 text-xs bg-green-500/15 dark:bg-green-600/10 text-green-700 dark:text-green-600/90 border border-green-500/25 dark:border-green-700/25">
|
||||
<div className="text-center w-[130px] rounded capitalize py-1 text-xs bg-green/15 text-green border border-green/25">
|
||||
Subscribed
|
||||
</div>
|
||||
) : (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="text-center w-[130px] rounded capitalize py-1 text-xs bg-red-500/10 text-red-600 dark:text-red-700/90 border border-red-600/10">
|
||||
<div className="text-center w-[130px] rounded capitalize py-1 text-xs bg-red/10 text-red border border-red/10">
|
||||
Unsubscribed
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
@@ -166,7 +166,7 @@ export default function ContactList({
|
||||
<p>
|
||||
{getUnsubscribeReason(
|
||||
contact.unsubscribeReason ??
|
||||
UnsubscribeReason.UNSUBSCRIBED
|
||||
UnsubscribeReason.UNSUBSCRIBED,
|
||||
)}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
|
@@ -66,7 +66,7 @@ export const DeleteContact: React.FC<{
|
||||
onError: (e) => {
|
||||
toast.error(`Contact not deleted: ${e.message}`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ export const DeleteContact: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Trash2 className="h-4 w-4 text-red-600/80" />
|
||||
<Trash2 className="h-4 w-4 text-red/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -46,7 +46,7 @@ export const DeleteContactBook: React.FC<{
|
||||
});
|
||||
|
||||
async function onContactBookDelete(
|
||||
values: z.infer<typeof contactBookSchema>
|
||||
values: z.infer<typeof contactBookSchema>,
|
||||
) {
|
||||
if (values.name !== contactBook.name) {
|
||||
contactBookForm.setError("name", {
|
||||
@@ -65,7 +65,7 @@ export const DeleteContactBook: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`Contact book deleted`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ export const DeleteContactBook: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="p-0 hover:bg-transparent ">
|
||||
<Trash2 className="h-[18px] w-[18px] text-red-600/80 hover:text-red-600/70" />
|
||||
<Trash2 className="h-[18px] w-[18px] text-red/80 hover:text-red/70" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -15,7 +15,6 @@ import { EmailStatus } from "@prisma/client";
|
||||
import { api } from "~/trpc/react";
|
||||
import Spinner from "@unsend/ui/src/spinner";
|
||||
import { useTheme } from "@unsend/ui";
|
||||
import { EMAIL_COLORS } from "~/lib/constants/colors";
|
||||
import { useColors } from "./hooks/useColors";
|
||||
|
||||
interface EmailChartProps {
|
||||
@@ -127,7 +126,10 @@ export default function EmailChart({ days, domain }: EmailChartProps) {
|
||||
</p>
|
||||
{data.delivered ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-2.5 h-2.5 bg-[#40a02bcc] dark:bg-[#a6e3a1] rounded-[2px]"></div>
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[2px]"
|
||||
style={{ backgroundColor: currentColors.delivered }}
|
||||
></div>
|
||||
<p className="text-xs text-muted-foreground w-[70px]">
|
||||
Delivered
|
||||
</p>
|
||||
@@ -136,7 +138,10 @@ export default function EmailChart({ days, domain }: EmailChartProps) {
|
||||
) : null}
|
||||
{data.bounced ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-2.5 h-2.5 bg-[#d20f39cc] dark:bg-[#f38ba8] rounded-[2px]"></div>
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[2px]"
|
||||
style={{ backgroundColor: currentColors.bounced }}
|
||||
></div>
|
||||
<p className="text-xs text-muted-foreground w-[70px]">
|
||||
Bounced
|
||||
</p>
|
||||
@@ -145,7 +150,12 @@ export default function EmailChart({ days, domain }: EmailChartProps) {
|
||||
) : null}
|
||||
{data.complained ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-2.5 h-2.5 bg-[#df8e1dcc] dark:bg-[#F9E2AF] rounded-[2px]"></div>
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[2px]"
|
||||
style={{
|
||||
backgroundColor: currentColors.complained,
|
||||
}}
|
||||
></div>
|
||||
<p className="text-xs text-muted-foreground w-[70px]">
|
||||
Complained
|
||||
</p>
|
||||
@@ -154,7 +164,10 @@ export default function EmailChart({ days, domain }: EmailChartProps) {
|
||||
) : null}
|
||||
{data.opened ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-2.5 h-2.5 bg-[#8839efcc] dark:bg-[#cba6f7] rounded-[2px]"></div>
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[2px]"
|
||||
style={{ backgroundColor: currentColors.opened }}
|
||||
></div>
|
||||
<p className="text-xs text-muted-foreground w-[70px]">
|
||||
Opened
|
||||
</p>
|
||||
@@ -163,7 +176,10 @@ export default function EmailChart({ days, domain }: EmailChartProps) {
|
||||
) : null}
|
||||
{data.clicked ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-2.5 h-2.5 bg-[#04a5e5cc] dark:bg-[#93c5fd] rounded-[2px]"></div>
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[2px]"
|
||||
style={{ backgroundColor: currentColors.clicked }}
|
||||
></div>
|
||||
<p className="text-xs text-muted-foreground w-[70px]">
|
||||
Clicked
|
||||
</p>
|
||||
@@ -236,16 +252,34 @@ const EmailChartItem: React.FC<DashboardItemCardProps> = ({
|
||||
count,
|
||||
percentage,
|
||||
}) => {
|
||||
const color = EMAIL_COLORS[status];
|
||||
const currentColors = useColors();
|
||||
|
||||
const getColorForStatus = (status: EmailStatus | "total"): string => {
|
||||
switch (status) {
|
||||
case "DELIVERED":
|
||||
return currentColors.delivered;
|
||||
case "BOUNCED":
|
||||
return currentColors.bounced;
|
||||
case "COMPLAINED":
|
||||
return currentColors.complained;
|
||||
case "OPENED":
|
||||
return currentColors.opened;
|
||||
case "CLICKED":
|
||||
return currentColors.clicked;
|
||||
case "total":
|
||||
default:
|
||||
return "#6b7280"; // gray-500 for total and other statuses
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-3 items-stretch font-mono">
|
||||
{/* <div className={`${color} w-0.5 rounded-full`}></div> */}
|
||||
|
||||
<div>
|
||||
<div className=" flex items-center gap-2">
|
||||
<div className={`${color} w-2.5 h-2.5 rounded-[3px]`}></div>
|
||||
{/* <div className={`${color} w-0.5 rounded-full`}></div> */}
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-[3px]"
|
||||
style={{ backgroundColor: getColorForStatus(status) }}
|
||||
></div>
|
||||
|
||||
<div className="text-xs uppercase text-muted-foreground ">
|
||||
{status.toLowerCase()}
|
||||
|
@@ -62,7 +62,7 @@ export default function AddApiKey() {
|
||||
setApiKey(data);
|
||||
apiKeyForm.reset();
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ export default function AddApiKey() {
|
||||
onClick={handleCopy}
|
||||
>
|
||||
{isCopied ? (
|
||||
<CheckIcon className="h-4 w-4 text-green-500" />
|
||||
<CheckIcon className="h-4 w-4 text-green" />
|
||||
) : (
|
||||
<ClipboardCopy className="h-4 w-4" />
|
||||
)}
|
||||
|
@@ -62,7 +62,7 @@ export const DeleteApiKey: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`API key deleted`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export const DeleteApiKey: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Trash2 className="h-4 w-4 text-red-600/80" />
|
||||
<Trash2 className="h-4 w-4 text-red/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -42,7 +42,7 @@ export default function DomainItemPage({
|
||||
{
|
||||
refetchInterval: (q) => (q?.state.data?.isVerifying ? 10000 : false),
|
||||
refetchIntervalInBackground: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const verifyQuery = api.domain.startVerification.useMutation();
|
||||
@@ -54,7 +54,7 @@ export default function DomainItemPage({
|
||||
onSettled: () => {
|
||||
domainQuery.refetch();
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -232,7 +232,7 @@ const DomainSettings: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
const utils = api.useUtils();
|
||||
|
||||
const [clickTracking, setClickTracking] = React.useState(
|
||||
domain.clickTracking,
|
||||
domain.clickTracking
|
||||
);
|
||||
const [openTracking, setOpenTracking] = React.useState(domain.openTracking);
|
||||
|
||||
@@ -245,7 +245,7 @@ const DomainSettings: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
utils.domain.invalidate();
|
||||
toast.success("Click tracking updated");
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ const DomainSettings: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
utils.domain.invalidate();
|
||||
toast.success("Open tracking updated");
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return (
|
||||
@@ -303,24 +303,20 @@ const DomainSettings: React.FC<{ domain: Domain }> = ({ domain }) => {
|
||||
};
|
||||
|
||||
const DnsVerificationStatus: React.FC<{ status: string }> = ({ status }) => {
|
||||
let badgeColor = "bg-gray-400/10 text-gray-500 border-gray-400/10"; // Default color
|
||||
let badgeColor = "bg-gray/10 text-gray border-gray/10"; // Default color
|
||||
switch (status) {
|
||||
case DomainStatus.SUCCESS:
|
||||
badgeColor =
|
||||
"bg-green-500/15 dark:bg-green-600/10 text-green-700 dark:text-green-600/90 border border-green-500/25 dark:border-green-700/25";
|
||||
badgeColor = "bg-green/15 text-green border border-green/25";
|
||||
break;
|
||||
case DomainStatus.FAILED:
|
||||
badgeColor =
|
||||
"bg-red-500/10 text-red-600 dark:text-red-700/90 border border-red-600/10";
|
||||
badgeColor = "bg-red/10 text-red border border-red/10";
|
||||
break;
|
||||
case DomainStatus.TEMPORARY_FAILURE:
|
||||
case DomainStatus.PENDING:
|
||||
badgeColor =
|
||||
"bg-yellow-500/20 dark:bg-yellow-500/10 text-yellow-600 border border-yellow-600/10";
|
||||
badgeColor = "bg-yellow/20 text-yellow border border-yellow/10";
|
||||
break;
|
||||
default:
|
||||
badgeColor =
|
||||
"bg-gray-200/70 dark:bg-gray-400/10 text-gray-600 dark:text-gray-400 border border-gray-300 dark:border-gray-400/20";
|
||||
badgeColor = "bg-gray/10 text-gray border border-gray/20";
|
||||
}
|
||||
|
||||
return (
|
||||
|
@@ -3,24 +3,20 @@ import { DomainStatus } from "@prisma/client";
|
||||
export const DomainStatusBadge: React.FC<{ status: DomainStatus }> = ({
|
||||
status,
|
||||
}) => {
|
||||
let badgeColor = "bg-gray-400/10 text-gray-500 border-gray-400/10"; // Default color
|
||||
let badgeColor = "bg-gray/10 text-gray border-gray/10"; // Default color
|
||||
switch (status) {
|
||||
case DomainStatus.SUCCESS:
|
||||
badgeColor =
|
||||
"bg-green-500/15 dark:bg-green-600/10 text-green-700 dark:text-green-600/90 border border-green-500/25 dark:border-green-700/25";
|
||||
badgeColor = "bg-green/15 text-green border border-green/25";
|
||||
break;
|
||||
case DomainStatus.FAILED:
|
||||
badgeColor =
|
||||
"bg-red-500/10 text-red-600 dark:text-red-700/90 border border-red-600/10";
|
||||
badgeColor = "bg-red/10 text-red border border-red/10";
|
||||
break;
|
||||
case DomainStatus.TEMPORARY_FAILURE:
|
||||
case DomainStatus.PENDING:
|
||||
badgeColor =
|
||||
"bg-yellow-500/20 dark:bg-yellow-500/10 text-yellow-600 border border-yellow-600/10";
|
||||
badgeColor = "bg-yellow/20 text-yellow border border-yellow/10";
|
||||
break;
|
||||
default:
|
||||
badgeColor =
|
||||
"bg-gray-200/70 dark:bg-gray-400/10 text-gray-600 dark:text-gray-400 border border-gray-300 dark:border-gray-400/20";
|
||||
badgeColor = "bg-gray/70 text-gray border border-gray/20";
|
||||
}
|
||||
|
||||
return (
|
||||
|
@@ -3,23 +3,23 @@ import { DomainStatus } from "@prisma/client";
|
||||
export const StatusIndicator: React.FC<{ status: DomainStatus }> = ({
|
||||
status,
|
||||
}) => {
|
||||
let badgeColor = "bg-gray-400"; // Default color
|
||||
let badgeColor = "bg-gray"; // Default color
|
||||
switch (status) {
|
||||
case DomainStatus.NOT_STARTED:
|
||||
badgeColor = "bg-gray-400";
|
||||
badgeColor = "bg-gray";
|
||||
break;
|
||||
case DomainStatus.SUCCESS:
|
||||
badgeColor = "bg-emerald-500";
|
||||
badgeColor = "bg-green";
|
||||
break;
|
||||
case DomainStatus.FAILED:
|
||||
badgeColor = "bg-red-500";
|
||||
badgeColor = "bg-red";
|
||||
break;
|
||||
case DomainStatus.TEMPORARY_FAILURE:
|
||||
case DomainStatus.PENDING:
|
||||
badgeColor = "bg-yellow-500";
|
||||
badgeColor = "bg-yellow";
|
||||
break;
|
||||
default:
|
||||
badgeColor = "bg-gray-400";
|
||||
badgeColor = "bg-gray";
|
||||
}
|
||||
|
||||
return <div className={` w-[2px] ${badgeColor} my-1.5 rounded-full`}></div>;
|
||||
|
@@ -64,7 +64,7 @@ export const CancelEmail: React.FC<{
|
||||
onError: (e) => {
|
||||
toast.error(`Error cancelling email: ${e.message}`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export const CancelEmail: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Trash2 className="h-4 w-4 text-red-500" />
|
||||
<Trash2 className="h-4 w-4 text-red" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -46,12 +46,12 @@ import { SheetTitle, SheetDescription } from "@unsend/ui/src/sheet";
|
||||
/* Stupid hydrating error. And I so stupid to understand the stupid NextJS docs */
|
||||
const DynamicSheetWithNoSSR = dynamic(
|
||||
() => import("@unsend/ui/src/sheet").then((mod) => mod.Sheet),
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
const DynamicSheetContentWithNoSSR = dynamic(
|
||||
() => import("@unsend/ui/src/sheet").then((mod) => mod.SheetContent),
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
export default function EmailsList() {
|
||||
@@ -231,7 +231,7 @@ export default function EmailsList() {
|
||||
Scheduled at{" "}
|
||||
{formatDate(
|
||||
email.scheduledAt,
|
||||
"MMM dd'th', hh:mm a"
|
||||
"MMM dd'th', hh:mm a",
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -247,7 +247,7 @@ export default function EmailsList() {
|
||||
{email.latestStatus !== "SCHEDULED"
|
||||
? formatDate(
|
||||
email.scheduledAt ?? email.createdAt,
|
||||
"MMM do, hh:mm a"
|
||||
"MMM do, hh:mm a",
|
||||
)
|
||||
: "--"}
|
||||
</TableCell>
|
||||
@@ -301,39 +301,39 @@ const EmailIcon: React.FC<{ status: EmailStatus }> = ({ status }) => {
|
||||
case "SENT":
|
||||
return (
|
||||
// <div className="border border-gray-400/60 p-2 rounded-lg bg-gray-400/10">
|
||||
<Mail className="w-6 h-6 text-gray-500 " />
|
||||
<Mail className="w-6 h-6 text-gray" />
|
||||
// </div>
|
||||
);
|
||||
case "DELIVERED":
|
||||
return (
|
||||
// <div className="border border-emerald-600/60 p-2 rounded-lg bg-emerald-500/10">
|
||||
<MailCheck className="w-6 h-6 text-emerald-800" />
|
||||
<MailCheck className="w-6 h-6 text-green" />
|
||||
// </div>
|
||||
);
|
||||
case "BOUNCED":
|
||||
case "FAILED":
|
||||
return (
|
||||
// <div className="border border-red-600/60 p-2 rounded-lg bg-red-500/10">
|
||||
<MailX className="w-6 h-6 text-red-900" />
|
||||
<MailX className="w-6 h-6 text-red" />
|
||||
// </div>
|
||||
);
|
||||
case "CLICKED":
|
||||
return (
|
||||
// <div className="border border-cyan-600/60 p-2 rounded-lg bg-cyan-500/10">
|
||||
<MailSearch className="w-6 h-6 text-cyan-700" />
|
||||
<MailSearch className="w-6 h-6 text-blue" />
|
||||
// </div>
|
||||
);
|
||||
case "OPENED":
|
||||
return (
|
||||
// <div className="border border-indigo-600/60 p-2 rounded-lg bg-indigo-500/10">
|
||||
<MailOpen className="w-6 h-6 text-indigo-700" />
|
||||
<MailOpen className="w-6 h-6 text-purple" />
|
||||
// </div>
|
||||
);
|
||||
case "DELIVERY_DELAYED":
|
||||
case "COMPLAINED":
|
||||
return (
|
||||
// <div className="border border-yellow-600/60 p-2 rounded-lg bg-yellow-500/10">
|
||||
<MailWarning className="w-6 h-6 text-yellow-700" />
|
||||
<MailWarning className="w-6 h-6 text-yellow" />
|
||||
// </div>
|
||||
);
|
||||
default:
|
||||
|
@@ -37,7 +37,7 @@ function VerifySuccess() {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" />
|
||||
<CheckCircle2 className="h-4 w-4 text-green flex-shrink-0" />
|
||||
<p>Your account has been upgraded to the paid plan.</p>
|
||||
</div>
|
||||
<Link href="/settings/billing" className="mt-8">
|
||||
|
@@ -36,7 +36,7 @@ export const DeleteTeamInvite: React.FC<{
|
||||
onError: async (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export const DeleteTeamInvite: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Trash2 className="h-4 w-4 text-red-600/80" />
|
||||
<Trash2 className="h-4 w-4 text-red/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -38,7 +38,7 @@ export const DeleteTeamMember: React.FC<{
|
||||
onError: async (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ export const DeleteTeamMember: React.FC<{
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
{self ? (
|
||||
<LogOut className="h-4 w-4 text-red-600/80" />
|
||||
<LogOut className="h-4 w-4 text-red/80" />
|
||||
) : (
|
||||
<Trash2 className="h-4 w-4 text-red-600/80" />
|
||||
<Trash2 className="h-4 w-4 text-red/80" />
|
||||
)}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
@@ -67,7 +67,7 @@ export default function TeamMembersList() {
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="text-center w-[100px] rounded capitalize py-1 text-xs bg-green-500/15 dark:bg-green-600/10 text-green-700 dark:text-green-600/90 border border-green-500/25 dark:border-green-700/25">
|
||||
<div className="text-center w-[100px] rounded capitalize py-1 text-xs bg-green/15 text-green border border-green/25">
|
||||
Active
|
||||
</div>
|
||||
</TableCell>
|
||||
@@ -122,7 +122,7 @@ export default function TeamMembersList() {
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="text-center w-[100px] rounded capitalize py-1 text-xs bg-yellow-500/15 dark:bg-yellow-600/10 text-yellow-700 dark:text-yellow-600/90 border border-yellow-500/25 dark:border-yellow-700/25">
|
||||
<div className="text-center w-[100px] rounded capitalize py-1 text-xs bg-yellow/15 text-yellow border border-yellow/25">
|
||||
Pending
|
||||
</div>
|
||||
</TableCell>
|
||||
|
@@ -29,7 +29,7 @@ export default function EditTemplatePage({
|
||||
{ templateId: templateId },
|
||||
{
|
||||
enabled: !!templateId,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
@@ -63,7 +63,7 @@ function TemplateEditor({
|
||||
const utils = api.useUtils();
|
||||
|
||||
const [json, setJson] = useState<Record<string, any> | undefined>(
|
||||
template.content ? JSON.parse(template.content) : undefined
|
||||
template.content ? JSON.parse(template.content) : undefined,
|
||||
);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [name, setName] = useState(template.name);
|
||||
@@ -86,13 +86,13 @@ function TemplateEditor({
|
||||
|
||||
const deboucedUpdateTemplate = useDebouncedCallback(
|
||||
updateEditorContent,
|
||||
1000
|
||||
1000,
|
||||
);
|
||||
|
||||
const handleFileChange = async (file: File) => {
|
||||
if (file.size > IMAGE_SIZE_LIMIT) {
|
||||
throw new Error(
|
||||
`File should be less than ${IMAGE_SIZE_LIMIT / 1024 / 1024}MB`
|
||||
`File should be less than ${IMAGE_SIZE_LIMIT / 1024 / 1024}MB`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ function TemplateEditor({
|
||||
toast.error(`${e.message}. Reverting changes.`);
|
||||
setName(template.name);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -152,9 +152,9 @@ function TemplateEditor({
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500">
|
||||
{isSaving ? (
|
||||
<div className="h-2 w-2 bg-yellow-500 rounded-full" />
|
||||
<div className="h-2 w-2 bg-yellow rounded-full" />
|
||||
) : (
|
||||
<div className="h-2 w-2 bg-emerald-500 rounded-full" />
|
||||
<div className="h-2 w-2 bg-green rounded-full" />
|
||||
)}
|
||||
{formatDistanceToNow(template.updatedAt) === "less than a minute"
|
||||
? "just now"
|
||||
@@ -188,7 +188,7 @@ function TemplateEditor({
|
||||
toast.error(`${e.message}. Reverting changes.`);
|
||||
setSubject(template.subject);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
className="mt-1 py-1 text-sm block w-full outline-none border-b border-transparent focus:border-border bg-transparent"
|
||||
|
@@ -62,7 +62,7 @@ export const DeleteTemplate: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`Template deleted`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export const DeleteTemplate: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="p-0 hover:bg-transparent">
|
||||
<Trash2 className="h-[18px] w-[18px] text-red-600/80" />
|
||||
<Trash2 className="h-[18px] w-[18px] text-red/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -35,7 +35,7 @@ export const DuplicateTemplate: React.FC<{
|
||||
setOpen(false);
|
||||
toast.success(`Template duplicated`);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export const DuplicateTemplate: React.FC<{
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="p-0 hover:bg-transparent">
|
||||
<Copy className="h-[18px] w-[18px] text-blue-600/80" />
|
||||
<Copy className="h-[18px] w-[18px] text-blue/80" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
|
@@ -36,7 +36,7 @@ export const PlanDetails = () => {
|
||||
<ul className="mt-4 space-y-3">
|
||||
{perks.map((perk, index) => (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" />
|
||||
<CheckCircle2 className="h-4 w-4 text-green flex-shrink-0" />
|
||||
<span className="text-sm">{perk}</span>
|
||||
</li>
|
||||
))}
|
||||
|
@@ -52,7 +52,7 @@ export const UpgradeModal = () => {
|
||||
<ul className="space-y-2">
|
||||
{basicPlanPerks.map((perk, index) => (
|
||||
<li key={index} className="flex items-start gap-2">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0 mt-0.5" />
|
||||
<CheckCircle2 className="h-4 w-4 text-green flex-shrink-0 mt-0.5" />
|
||||
<span className="text-sm">{perk}</span>
|
||||
</li>
|
||||
))}
|
||||
|
Reference in New Issue
Block a user