Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"use client";
import { useTranslations } from "next-intl";


import { formatDateTooltip } from "@/lib/analytics/format-date-tooltip";
import { AnalyticsLoadingSpinner } from "@/ui/analytics/analytics-loading-spinner";
Expand Down Expand Up @@ -28,6 +30,8 @@ type Tab = {
};

export default function CommissionsPageClient() {
const t = useTranslations("admin-commissions-dashboard");

const { queryParams, getQueryString, searchParamsObj } = useRouterStuff();
const {
tab: selectedTab = "commissions",
Expand Down Expand Up @@ -292,9 +296,7 @@ export default function CommissionsPageClient() {
/>
</TimeSeriesChart>
) : (
<div className="text-center text-sm text-neutral-600">
No data available.
</div>
<div className="text-center text-sm text-neutral-600">{t('messages.no-data-available')}</div>
)
) : (
<AnalyticsLoadingSpinner />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useTranslations } from "next-intl";
import { Button, InfoTooltip } from "@dub/ui";
import { currencyFormatter } from "@dub/utils";

Expand All @@ -8,19 +9,21 @@ export function ReferralsEmbedEarningsSummary({
earnings: { upcoming: number; paid: number };
programSlug: string;
}) {
const t = useTranslations("referrals-embed-earnings");

return (
<div className="border-border-subtle bg-bg-default flex flex-col justify-between gap-4 rounded-lg border p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<p className="text-content-subtle text-sm">Earnings</p>
<p className="text-content-subtle text-sm">{t('headings.earnings')}</p>
<InfoTooltip content="Summary of your commission earnings from your referrals." />
</div>
<a
href={`https://partners.dub.co/${programSlug}/register`}
target="_blank"
>
<Button
text="Settings"
text={t('buttons.settings')}
variant="secondary"
className="h-7 p-2 text-sm"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useTranslations } from "next-intl";
import { FramerButton } from "@/ui/auth/login/framer-button";
import { APP_DOMAIN, constructMetadata } from "@dub/utils";
import Link from "next/link";
Expand All @@ -8,28 +9,27 @@ export const metadata = constructMetadata({
});

export default function CustomPartnerLoginPage() {
const t = useTranslations("framer-partner-login");

return (
<div className="mx-auto my-10 flex w-full max-w-sm flex-col gap-8">
<div className="animate-slide-up-fade relative flex w-auto flex-col items-center [--offset:10px] [animation-duration:1.3s] [animation-fill-mode:both]">
<img
src="https://assets.dub.co/testimonials/companies/framer.svg"
alt="Framer Logo"
alt={t('logo.alt-text')}
className="h-8"
/>
</div>
<div className="animate-slide-up-fade flex flex-col items-center justify-center gap-2 [--offset:10px] [animation-delay:0.15s] [animation-duration:1.3s] [animation-fill-mode:both]">
<h1 className="text-lg font-medium text-neutral-800">
Sign in to Framer Partners
</h1>
<p className="text-center text-sm text-neutral-700">
Not a Framer Partner?&nbsp;
<Link
<h1 className="text-lg font-medium text-neutral-800">{t('headings.sign-in-title')}</h1>
<p className="text-center text-sm text-neutral-700">{t.rich('messages.not-partner-apply', {
component0: (chunks) => <Link
href="https://www.framer.com/creators"
target="_blank"
className="font-normal underline underline-offset-2 transition-colors hover:text-black"
>
Apply today
</Link>
>{chunks}</Link>
})}

</p>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getTranslations } from "next-intl/server";
import { getProgram } from "@/lib/fetchers/get-program";
import { programLanderSchema } from "@/lib/zod/schemas/program-lander";
import { PageContent } from "@/ui/layout/page-content";
Expand All @@ -13,6 +14,8 @@ export default async function ProgramDetailsPage({
}: {
params: { programSlug: string };
}) {
const t = await getTranslations("program-application-page");

const program = await getProgram({
slug: programSlug,
include: ["rewards", "defaultDiscount"],
Expand All @@ -23,7 +26,7 @@ export default async function ProgramDetailsPage({
return (
<PageContent>
<MaxWidthWrapper className="mb-10 mt-4">
<BackLink href="/programs">Programs</BackLink>
<BackLink href="/programs">{t('navigation.programs-breadcrumb')}</BackLink>
<div className="mt-8 grid grid-cols-1 gap-x-16 gap-y-10 lg:grid-cols-[300px_minmax(0,600px)]">
<div>
<ProgramSidebar program={program} />
Expand All @@ -40,14 +43,8 @@ export default async function ProgramDetailsPage({
>
{/* Hero section */}
<div className="grid grid-cols-1 gap-5">
<h1 className="text-4xl font-semibold">
Join the {program.name} affiliate program
</h1>
<p className="text-base text-neutral-700">
Share {program.name} with your audience and for each
subscription generated through your referral, you'll earn a
share of the revenue on any plans they purchase.
</p>
<h1 className="text-4xl font-semibold">{t('headings.join-program-title', { "programName": program.name })}</h1>
<p className="text-base text-neutral-700">{t('descriptions.affiliate-program-benefits', { "programName": program.name })}</p>
</div>

{/* Content blocks */}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"use client";
import { getTranslations } from "next-intl/server";


import { EmptyState, LoadingSpinner } from "@dub/ui";
import { useSession } from "next-auth/react";
Expand All @@ -7,6 +9,8 @@ import { useEffect, useRef } from "react";
import { toast } from "sonner";

export default async function ConfirmEmailChangePageClient() {
const t = await getTranslations("confirm-email-change");

const router = useRouter();
const { update, status } = useSession();
const hasUpdatedSession = useRef(false);
Expand All @@ -29,8 +33,8 @@ export default async function ConfirmEmailChangePageClient() {
return (
<EmptyState
icon={LoadingSpinner}
title="Verifying Email Change"
description="Verifying your email change request. This might take a few seconds..."
title={t('verification.title')}
description={t('verification.description')}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use client";
import { useTranslations } from "next-intl";


import { Button, useKeyboardShortcut } from "@dub/ui";
import { useInvitePartnerSheet } from "./invite-partner-sheet";

export function InvitePartnerButton() {
const t = useTranslations("invite-partner-button");

const { invitePartnerSheet, setIsOpen: setShowInvitePartnerSheet } =
useInvitePartnerSheet();

Expand All @@ -15,7 +19,7 @@ export function InvitePartnerButton() {
<Button
type="button"
onClick={() => setShowInvitePartnerSheet(true)}
text="Invite partner"
text={t('buttons.invite-partner')}
shortcut="P"
/>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"use client";
import { useTranslations } from "next-intl";


import useDiscounts from "@/lib/swr/use-discounts";
import useProgram from "@/lib/swr/use-program";
Expand All @@ -18,6 +20,8 @@ export function ProgramSettingsDiscountsPageClient() {
}

const DefaultDiscount = () => {
const t = useTranslations("program-discounts-settings");

const { program } = useProgram();
const { discounts, loading } = useDiscounts();

Expand All @@ -35,13 +39,9 @@ const DefaultDiscount = () => {
<div className="flex flex-col gap-6 px-6 py-8">
<div className="flex items-center justify-between">
<div>
<h2 className="inline-flex items-center gap-2 text-lg font-semibold text-neutral-900">
Referral Discount <Badge variant="gray">Default</Badge>
<h2 className="inline-flex items-center gap-2 text-lg font-semibold text-neutral-900">{t('headings.referral-discount')}<Badge variant="gray">{t('badges.default')}</Badge>
</h2>
<p className="mt-1 text-sm text-neutral-600">
The discount offered to all customers when referred by your
partners
</p>
<p className="mt-1 text-sm text-neutral-600">{t('descriptions.default-discount')}</p>
</div>
</div>

Expand All @@ -56,12 +56,10 @@ const DefaultDiscount = () => {
<div className="flex size-10 items-center justify-center rounded-full border border-neutral-300">
<BadgePercent className="size-5" />
</div>
<p className="text-sm text-neutral-600">
No default referral discount created
</p>
<p className="text-sm text-neutral-600">{t('messages.no-default-discount')}</p>
</div>
<Button
text="Create default discount"
text={t('buttons.create-default-discount')}
variant="primary"
className="h-8 w-fit px-3"
onClick={() => setIsOpen(true)}
Expand All @@ -77,6 +75,8 @@ const DefaultDiscount = () => {
};

const AdditionalDiscounts = () => {
const t = useTranslations("program-discounts-settings");

const { program } = useProgram();
const { discounts, loading } = useDiscounts();

Expand All @@ -93,15 +93,11 @@ const AdditionalDiscounts = () => {
<div className="flex flex-col gap-6 px-6 py-8">
<div className="flex items-center justify-between">
<div>
<h2 className="inline-flex items-center gap-2 text-lg font-semibold text-neutral-900">
Additional Referral Discounts
</h2>
<p className="mt-1 text-sm text-neutral-600">
Add additional discounts for your referred customers
</p>
<h2 className="inline-flex items-center gap-2 text-lg font-semibold text-neutral-900">{t('headings.additional-referral-discounts')}</h2>
<p className="mt-1 text-sm text-neutral-600">{t('descriptions.additional-discounts')}</p>
</div>
<Button
text="Create discount"
text={t('buttons.create-discount')}
variant="primary"
className="h-8 w-fit px-3"
onClick={() => setIsOpen(true)}
Expand Down Expand Up @@ -129,12 +125,8 @@ const AdditionalDiscounts = () => {
<BadgePercent className="size-6 text-neutral-800" />
</div>
<div className="flex flex-col items-center gap-1 px-4 text-center">
<p className="text-base font-medium text-neutral-900">
Additional Discounts
</p>
<p className="text-sm text-neutral-600">
No additional discounts have been added yet
</p>
<p className="text-base font-medium text-neutral-900">{t('headings.additional-discounts')}</p>
<p className="text-sm text-neutral-600">{t('messages.no-additional-discounts')}</p>
</div>
</div>
)}
Expand All @@ -151,6 +143,8 @@ const Discount = ({
discount: DiscountProps;
isDefault: boolean;
}) => {
const t = useTranslations("program-discounts-settings");

const { DiscountSheet, setIsOpen } = useDiscountSheet({
...(discount && { discount }),
isDefault,
Expand All @@ -172,9 +166,9 @@ const Discount = ({
</span>
</div>
{discount.partnersCount && discount?.partnersCount > 0 ? (
<Badge variant="green">{discount.partnersCount} partners</Badge>
<Badge variant="green">{t('badges.partners-count', { "discountPartnersCount": discount.partnersCount })}</Badge>
) : (
<Badge variant="gray">All partners</Badge>
<Badge variant="gray">{t('badges.all-partners')}</Badge>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"use client";
import { useTranslations } from "next-intl";


import { clientAccessCheck } from "@/lib/api/tokens/permissions";
import useDomains from "@/lib/swr/use-domains";
Expand Down Expand Up @@ -32,6 +34,8 @@ import { ChevronDown, Crown } from "lucide-react";
import { useEffect, useState } from "react";

export function CustomDomains() {
const t = useTranslations("domains-settings");

const {
id: workspaceId,
plan,
Expand Down Expand Up @@ -79,10 +83,7 @@ export function CustomDomains() {

const disabledTooltip = exceededDomains ? (
<TooltipContent
title={`You can only add up to ${domainsLimit} ${pluralize(
"domain",
domainsLimit || 0,
)} on the ${capitalize(plan)} plan. Upgrade to add more domains`}
title={t('limits.upgrade-required-message', { "domainsLimit": domainsLimit, "domainsLimit0": domainsLimit || 0, "capitalizePlan": capitalize(plan) })}
cta="Upgrade"
onClick={() => {
queryParams({
Expand Down Expand Up @@ -131,28 +132,24 @@ export function CustomDomains() {
content={
<div className="grid w-screen gap-px p-2 sm:w-fit sm:min-w-[17rem]">
<Button
text="Connect a domain you own"
text={t('buttons.connect-domain')}
variant="outline"
icon={<Globe className="h-4 w-4" />}
className="h-9 justify-start px-2 text-neutral-800"
onClick={() => setShowAddEditDomainModal(true)}
/>
<Button
text={
<div className="flex items-center gap-3">
Claim free .link domain
{plan === "free" ? (
<div className="flex items-center gap-3">{t('buttons.claim-free-link-domain')}{plan === "free" ? (
<Badge
variant="neutral"
className="flex items-center gap-1"
>
<Crown className="size-3" />
<span className="uppercase">Pro</span>
<span className="uppercase">{t('badges.pro-plan')}</span>
</Badge>
) : dotLinkClaimed ? (
<span className="rounded-md border border-green-200 bg-green-500/10 px-1 py-0.5 text-xs text-green-900">
Claimed
</span>
<span className="rounded-md border border-green-200 bg-green-500/10 px-1 py-0.5 text-xs text-green-900">{t('badges.claimed-status')}</span>
) : null}
</div>
}
Expand All @@ -172,8 +169,7 @@ export function CustomDomains() {
variant="primary"
className="h-9 w-fit rounded-lg"
text={
<div className="flex items-center gap-2">
Add custom domain{" "}
<div className="flex items-center gap-2">{t('buttons.add-custom-domain')}
<ChevronDown className="size-4 transition-transform duration-75 group-data-[state=open]:rotate-180" />
</div>
}
Expand Down Expand Up @@ -207,18 +203,14 @@ export function CustomDomains() {
<div className="flex flex-col items-center gap-4 rounded-xl border border-neutral-200 py-10">
<EmptyState
icon={Globe}
title={
archived
? "No archived domains found"
: "No custom domains found"
}
title={archived ? t('empty-states.no-domains-conditional_0') : t('empty-states.no-domains-conditional_1')}
/>
<AddDomainButton />
</div>
) : (
<AnimatedEmptyState
title="No custom domains found"
description="Use custom domains for better brand recognition and click-through rates"
title={t('empty-states.no-custom-domains')}
description={t('empty-states.custom-domains-description')}
cardContent={
<>
<Globe className="size-4 text-neutral-700" />
Expand Down
Loading