chore: extract more strings (#933)
This commit is contained in:
parent
4ce4b141b4
commit
bee41b242b
8 changed files with 146 additions and 99 deletions
|
@ -1,28 +1,32 @@
|
|||
import { CodeIcon, CreditCardIcon, KeyIcon, UserGroupIcon, UserIcon } from "@heroicons/react/solid";
|
||||
import React from "react";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import NavTabs from "./NavTabs";
|
||||
|
||||
export default function SettingsShell({ children }: { children: React.ReactNode }) {
|
||||
const { t } = useLocale();
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: "Profile",
|
||||
name: t("profile"),
|
||||
href: "/settings/profile",
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
name: "Security",
|
||||
name: t("security"),
|
||||
href: "/settings/security",
|
||||
icon: KeyIcon,
|
||||
},
|
||||
{ name: "Embed & Webhooks", href: "/settings/embed", icon: CodeIcon },
|
||||
{ name: t("embed_and_webhooks"), href: "/settings/embed", icon: CodeIcon },
|
||||
{
|
||||
name: "Teams",
|
||||
name: t("teams"),
|
||||
href: "/settings/teams",
|
||||
icon: UserGroupIcon,
|
||||
},
|
||||
{
|
||||
name: "Billing",
|
||||
name: t("billing"),
|
||||
href: "/settings/billing",
|
||||
icon: CreditCardIcon,
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
|
|||
<div className="flex flex-row items-center">
|
||||
<h2 className="font-cal text-lg leading-6 font-medium text-gray-900">{t("2fa")}</h2>
|
||||
<Badge className="text-xs ml-2" variant={enabled ? "success" : "gray"}>
|
||||
{enabled ? "Enabled" : "Disabled"}
|
||||
{enabled ? t("enabled") : t("disabled")}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="mt-1 text-sm text-gray-500">{t("add_an_extra_layer_of_security")}</p>
|
||||
|
@ -28,7 +28,7 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
|
|||
className="mt-6"
|
||||
type="submit"
|
||||
onClick={() => (enabled ? setDisableModalOpen(true) : setEnableModalOpen(true))}>
|
||||
{enabled ? "Disable" : "Enable"} {t("2fa")}
|
||||
{enabled ? t("disable") : t("enable")} {t("2fa")}
|
||||
</Button>
|
||||
|
||||
{enableModalOpen && (
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { ExternalLinkIcon } from "@heroicons/react/solid";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { getOrSetUserLocaleFromHeaders } from "@lib/core/i18n/i18n.utils";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import prisma from "@lib/prisma";
|
||||
|
||||
import SettingsShell from "@components/SettingsShell";
|
||||
|
@ -9,24 +12,26 @@ import Shell from "@components/Shell";
|
|||
import Button from "@components/ui/Button";
|
||||
|
||||
export default function Billing() {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<Shell heading="Billing" subtitle="Manage your billing information and cancel your subscription.">
|
||||
<Shell heading={t("billing")} subtitle={t("manage_your_billing_info")}>
|
||||
<SettingsShell>
|
||||
<div className="py-6 lg:pb-8 lg:col-span-9">
|
||||
<div className="bg-white border sm:rounded-sm">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||
View and manage your billing details
|
||||
{t("view_and_manage_billing_details")}
|
||||
</h3>
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>View and edit your billing details, as well as cancel your subscription.</p>
|
||||
<p>{t("view_and_edit_billing_details")}</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<form
|
||||
method="POST"
|
||||
action={`${process.env.NEXT_PUBLIC_BASE_URL}/api/integrations/stripepayment/portal`}>
|
||||
<Button type="submit">
|
||||
Go to the billing portal <ExternalLinkIcon className="ml-1 w-4 h-4" />
|
||||
{t("go_to_billing_portal")} <ExternalLinkIcon className="ml-1 w-4 h-4" />
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -34,13 +39,13 @@ export default function Billing() {
|
|||
</div>
|
||||
<div className="mt-4 bg-gray-50 sm:rounded-sm border">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">Need anything else?</h3>
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">{t("need_anything_else")}</h3>
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>If you need any further help with billing, our support team are here to help.</p>
|
||||
<p>{t("further_billing_help")}</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Button href="mailto:help@cal.com" color="secondary" type="submit">
|
||||
Contact our support team
|
||||
{t("contact_our_support_team")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -53,6 +58,8 @@ export default function Billing() {
|
|||
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const session = await getSession(context);
|
||||
const locale = await getOrSetUserLocaleFromHeaders(context.req);
|
||||
|
||||
if (!session) {
|
||||
return { redirect: { permanent: false, destination: "/auth/login" } };
|
||||
}
|
||||
|
@ -74,6 +81,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
});
|
||||
|
||||
return {
|
||||
props: { session, user },
|
||||
props: {
|
||||
session,
|
||||
user,
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { PlusIcon } from "@heroicons/react/outline";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useSession } from "next-auth/client";
|
||||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { getOrSetUserLocaleFromHeaders } from "@lib/core/i18n/i18n.utils";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import prisma from "@lib/prisma";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import { Webhook } from "@lib/webhook";
|
||||
|
@ -19,6 +22,7 @@ import WebhookList from "@components/webhook/WebhookList";
|
|||
|
||||
export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const [, loading] = useSession();
|
||||
const { t } = useLocale();
|
||||
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const [bookingCreated, setBookingCreated] = useState(true);
|
||||
|
@ -52,7 +56,9 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
}
|
||||
|
||||
const iframeTemplate = `<iframe src="${process.env.NEXT_PUBLIC_APP_URL}/${props.user?.username}" frameborder="0" allowfullscreen></iframe>`;
|
||||
const htmlTemplate = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Schedule a meeting</title><style>body {margin: 0;}iframe {height: calc(100vh - 4px);width: calc(100vw - 4px);box-sizing: border-box;}</style></head><body>${iframeTemplate}</body></html>`;
|
||||
const htmlTemplate = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${t(
|
||||
"schedule_a_meeting"
|
||||
)}</title><style>body {margin: 0;}iframe {height: calc(100vh - 4px);width: calc(100vw - 4px);box-sizing: border-box;}</style></head><body>${iframeTemplate}</body></html>`;
|
||||
const handleErrors = async (resp: Response) => {
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json();
|
||||
|
@ -106,26 +112,24 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
};
|
||||
|
||||
return (
|
||||
<Shell
|
||||
heading="Embed & Webhooks"
|
||||
subtitle="Integrate with your website using our embed options, or get real-time booking information using custom webhooks.">
|
||||
<Shell heading={t("embed_and_webhooks")} subtitle={t("integrate_using_embed_or_webhooks")}>
|
||||
<SettingsShell>
|
||||
{!editWebhookEnabled && (
|
||||
<div className="py-6 lg:pb-8 lg:col-span-9">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">iframe Embed</h2>
|
||||
<p className="mt-1 text-sm text-gray-500">The easiest way to embed Cal.com on your website.</p>
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">{t("iframe_embed")}</h2>
|
||||
<p className="mt-1 text-sm text-gray-500">{t("embed_calcom")}</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 space-x-4">
|
||||
<div>
|
||||
<label htmlFor="iframe" className="block text-sm font-medium text-gray-700">
|
||||
Standard iframe
|
||||
{t("standard_iframe")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<textarea
|
||||
id="iframe"
|
||||
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
||||
placeholder="Loading..."
|
||||
placeholder={t("loading")}
|
||||
defaultValue={iframeTemplate}
|
||||
readOnly
|
||||
/>
|
||||
|
@ -133,13 +137,13 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="fullscreen" className="block text-sm font-medium text-gray-700">
|
||||
Responsive full screen iframe
|
||||
{t("responsive_fullscreen_iframe")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<textarea
|
||||
id="fullscreen"
|
||||
className="block w-full h-32 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-black sm:text-sm"
|
||||
placeholder="Loading..."
|
||||
placeholder={t("loading")}
|
||||
defaultValue={htmlTemplate}
|
||||
readOnly
|
||||
/>
|
||||
|
@ -150,26 +154,23 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
<div className="flex justify-between my-6">
|
||||
<div>
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">Webhooks</h2>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Receive Cal meeting data at a specified URL, in real-time, when an event is scheduled or
|
||||
cancelled.{" "}
|
||||
</p>
|
||||
<p className="mt-1 text-sm text-gray-500">{t("receive_cal_meeting_data")} </p>
|
||||
</div>
|
||||
<div>
|
||||
<Dialog>
|
||||
<DialogTrigger className="px-4 py-2 my-6 text-sm font-medium text-white border border-transparent rounded-sm shadow-sm bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
|
||||
<PlusIcon className="inline w-5 h-5 mr-1" />
|
||||
New Webhook
|
||||
{t("new_webhook")}
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader
|
||||
title="Create a new webhook"
|
||||
subtitle="Create a new webhook to your account"
|
||||
title={t("create_new_webhook")}
|
||||
subtitle={t("create_new_webhook_to_account")}
|
||||
/>
|
||||
<div className="my-4">
|
||||
<div className="mb-4">
|
||||
<label htmlFor="subUrl" className="block text-sm font-medium text-gray-700">
|
||||
Subscriber Url
|
||||
{t("subscriber_url")}
|
||||
</label>
|
||||
<input
|
||||
ref={subUrlRef}
|
||||
|
@ -182,12 +183,12 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
/>
|
||||
<legend className="block pt-4 mb-2 text-sm font-medium text-gray-700">
|
||||
{" "}
|
||||
Event Triggers{" "}
|
||||
{t("event_triggers")}{" "}
|
||||
</legend>
|
||||
<div className="p-2 border border-gray-300 rounded-sm">
|
||||
<div className="flex pb-4">
|
||||
<div className="w-10/12">
|
||||
<h2 className="font-medium text-gray-800">Booking Created</h2>
|
||||
<h2 className="font-medium text-gray-800">{t("booking_created")}</h2>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-2/12 text-right">
|
||||
<Switch
|
||||
|
@ -202,7 +203,7 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
</div>
|
||||
<div className="flex py-1">
|
||||
<div className="w-10/12">
|
||||
<h2 className="font-medium text-gray-800">Booking Rescheduled</h2>
|
||||
<h2 className="font-medium text-gray-800">{t("booking_rescheduled")}</h2>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-2/12 text-right">
|
||||
<Switch
|
||||
|
@ -217,7 +218,7 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
</div>
|
||||
<div className="flex pt-4">
|
||||
<div className="w-10/12">
|
||||
<h2 className="font-medium text-gray-800">Booking Cancelled</h2>
|
||||
<h2 className="font-medium text-gray-800">{t("booking_cancelled")}</h2>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-2/12 text-right">
|
||||
<Switch
|
||||
|
@ -240,11 +241,11 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
onClick={createWebhook}
|
||||
color="primary"
|
||||
className="ml-2">
|
||||
Create Webhook
|
||||
{t("create_webhook")}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button color="secondary">Cancel</Button>
|
||||
<Button color="secondary">{t("cancel")}</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -272,12 +273,10 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
<hr className="mt-8" />
|
||||
<div className="my-6">
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">Cal.com API</h2>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Leverage our API for full control and customizability.
|
||||
</p>
|
||||
<p className="mt-1 text-sm text-gray-500">{t("leverage_our_api")}</p>
|
||||
</div>
|
||||
<a href="https://developer.cal.com/api" className="btn btn-primary">
|
||||
Browse our API documentation
|
||||
{t("browse_api_documentation")}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
@ -289,6 +288,8 @@ export default function Embed(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const session = await getSession(context);
|
||||
const locale = await getOrSetUserLocaleFromHeaders(context.req);
|
||||
|
||||
if (!session?.user?.email) {
|
||||
return { redirect: { permanent: false, destination: "/auth/login" } };
|
||||
}
|
||||
|
@ -310,6 +311,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
});
|
||||
|
||||
return {
|
||||
props: { session, user },
|
||||
props: {
|
||||
session,
|
||||
user,
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
localeOptions,
|
||||
OptionType,
|
||||
} from "@lib/core/i18n/i18n.utils";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import { isBrandingHidden } from "@lib/isBrandingHidden";
|
||||
import showToast from "@lib/notification";
|
||||
import prisma from "@lib/prisma";
|
||||
|
@ -30,17 +31,9 @@ import Badge from "@components/ui/Badge";
|
|||
import Button from "@components/ui/Button";
|
||||
import { UsernameInput } from "@components/ui/UsernameInput";
|
||||
|
||||
const themeOptions = [
|
||||
{ value: "light", label: "Light" },
|
||||
{ value: "dark", label: "Dark" },
|
||||
];
|
||||
|
||||
type Props = inferSSRProps<typeof getServerSideProps>;
|
||||
function HideBrandingInput(props: {
|
||||
//
|
||||
hideBrandingRef: RefObject<HTMLInputElement>;
|
||||
user: Props["user"];
|
||||
}) {
|
||||
function HideBrandingInput(props: { hideBrandingRef: RefObject<HTMLInputElement>; user: Props["user"] }) {
|
||||
const { t } = useLocale();
|
||||
const [modelOpen, setModalOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
|
@ -72,19 +65,16 @@ function HideBrandingInput(props: {
|
|||
<div className="sm:flex sm:items-start mb-4">
|
||||
<div className="mt-3 sm:mt-0 sm:text-left">
|
||||
<h3 className="font-cal text-lg leading-6 font-bold text-gray-900" id="modal-title">
|
||||
This feature is only available in Pro plan
|
||||
{t("only_available_on_pro_plan")}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-3">
|
||||
<p>
|
||||
In order to remove the Cal branding from your booking pages, you need to upgrade to a paid
|
||||
account.
|
||||
</p>
|
||||
<p>{t("remove_cal_branding_description")}</p>
|
||||
|
||||
<p>
|
||||
{" "}
|
||||
To upgrade go to{" "}
|
||||
{t("to_upgrade_go_to")}{" "}
|
||||
<a href="https://cal.com/upgrade" className="underline">
|
||||
cal.com/upgrade
|
||||
</a>
|
||||
|
@ -96,7 +86,7 @@ function HideBrandingInput(props: {
|
|||
<Button
|
||||
className="btn-wide btn-primary text-center table-cell"
|
||||
onClick={() => setModalOpen(false)}>
|
||||
Dismiss
|
||||
{t("dismiss")}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
|
@ -107,8 +97,14 @@ function HideBrandingInput(props: {
|
|||
}
|
||||
|
||||
export default function Settings(props: Props) {
|
||||
const { t } = useLocale();
|
||||
const mutation = trpc.useMutation("viewer.updateProfile");
|
||||
|
||||
const themeOptions = [
|
||||
{ value: "light", label: t("light") },
|
||||
{ value: "dark", label: t("dark") },
|
||||
];
|
||||
|
||||
const usernameRef = useRef<HTMLInputElement>(null);
|
||||
const nameRef = useRef<HTMLInputElement>(null);
|
||||
const descriptionRef = useRef<HTMLTextAreaElement>();
|
||||
|
@ -178,7 +174,7 @@ export default function Settings(props: Props) {
|
|||
locale: enteredLanguage,
|
||||
})
|
||||
.then(() => {
|
||||
showToast("Your user profile has been updated successfully", "success");
|
||||
showToast(t("your_user_profile_updated_successfully"), "success");
|
||||
setHasErrors(false); // dismiss any open errors
|
||||
})
|
||||
.catch((err) => {
|
||||
|
@ -189,7 +185,7 @@ export default function Settings(props: Props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<Shell heading="Profile" subtitle="Edit your profile information, which shows on your scheduling link.">
|
||||
<Shell heading={t("profile")} subtitle={t("edit_profile_info_description")}>
|
||||
<SettingsShell>
|
||||
<form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={updateProfileHandler}>
|
||||
{hasErrors && <Alert severity="error" title={errorMessage} />}
|
||||
|
@ -202,7 +198,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div className="w-full sm:w-1/2 sm:ml-2">
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||
Full name
|
||||
{t("full_name")}
|
||||
</label>
|
||||
<input
|
||||
ref={nameRef}
|
||||
|
@ -210,7 +206,7 @@ export default function Settings(props: Props) {
|
|||
name="name"
|
||||
id="name"
|
||||
autoComplete="given-name"
|
||||
placeholder="Your name"
|
||||
placeholder={t("your_name")}
|
||||
required
|
||||
className="mt-1 block w-full border border-gray-300 rounded-sm shadow-sm py-2 px-3 focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
||||
defaultValue={props.user.name}
|
||||
|
@ -221,19 +217,19 @@ export default function Settings(props: Props) {
|
|||
<div className="block sm:flex">
|
||||
<div className="w-full sm:w-1/2 sm:mr-2 mb-6">
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Email
|
||||
{t("email")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
id="email"
|
||||
placeholder="Your email"
|
||||
placeholder={t("your_email")}
|
||||
disabled
|
||||
className="mt-1 block w-full py-2 px-3 text-gray-500 border border-gray-300 rounded-l-sm bg-gray-50 sm:text-sm"
|
||||
defaultValue={props.user.email}
|
||||
/>
|
||||
<p className="mt-2 text-sm text-gray-500" id="email-description">
|
||||
To change your email, please contact{" "}
|
||||
{t("change_email_contact")}{" "}
|
||||
<a className="text-blue-500" href="mailto:help@cal.com">
|
||||
help@cal.com
|
||||
</a>
|
||||
|
@ -243,14 +239,14 @@ export default function Settings(props: Props) {
|
|||
|
||||
<div>
|
||||
<label htmlFor="about" className="block text-sm font-medium text-gray-700">
|
||||
About
|
||||
{t("about")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<textarea
|
||||
ref={descriptionRef}
|
||||
id="about"
|
||||
name="about"
|
||||
placeholder="A little something about yourself."
|
||||
placeholder={t("little_something_about")}
|
||||
rows={3}
|
||||
defaultValue={props.user.bio}
|
||||
className="shadow-sm focus:ring-neutral-500 focus:border-neutral-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-sm"></textarea>
|
||||
|
@ -276,7 +272,7 @@ export default function Settings(props: Props) {
|
|||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg="Change avatar"
|
||||
buttonMsg={t("change_avatar")}
|
||||
handleAvatarChange={handleAvatarChange}
|
||||
imageSrc={imageSrc}
|
||||
/>
|
||||
|
@ -285,7 +281,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="language" className="block text-sm font-medium text-gray-700">
|
||||
Language
|
||||
{t("language")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<Select
|
||||
|
@ -300,7 +296,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
||||
Timezone
|
||||
{t("timezone")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<TimezoneSelect
|
||||
|
@ -314,7 +310,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="weekStart" className="block text-sm font-medium text-gray-700">
|
||||
First Day of Week
|
||||
{t("first_day_of_week")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<Select
|
||||
|
@ -324,15 +320,15 @@ export default function Settings(props: Props) {
|
|||
classNamePrefix="react-select"
|
||||
className="react-select-container border border-gray-300 rounded-sm shadow-sm focus:ring-neutral-500 focus:border-neutral-500 mt-1 block w-full sm:text-sm"
|
||||
options={[
|
||||
{ value: "Sunday", label: "Sunday" },
|
||||
{ value: "Monday", label: "Monday" },
|
||||
{ value: "Sunday", label: t("sunday") },
|
||||
{ value: "Monday", label: t("monday") },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="theme" className="block text-sm font-medium text-gray-700">
|
||||
Single Theme
|
||||
{t("single_theme")}
|
||||
</label>
|
||||
<div className="my-1">
|
||||
<Select
|
||||
|
@ -358,7 +354,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div className="ml-3 text-sm">
|
||||
<label htmlFor="theme-adjust-os" className="font-medium text-gray-700">
|
||||
Automatically adjust theme based on invitee preferences
|
||||
{t("automatically_adjust_theme")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -370,10 +366,10 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<div className="ml-3 text-sm">
|
||||
<label htmlFor="hide-branding" className="font-medium text-gray-700">
|
||||
Disable Cal.com branding{" "}
|
||||
{t("disable_cal_branding")}{" "}
|
||||
{props.user.plan !== "PRO" && <Badge variant="default">PRO</Badge>}
|
||||
</label>
|
||||
<p className="text-gray-500">Hide all Cal.com branding from your public pages.</p>
|
||||
<p className="text-gray-500">{t("disable_cal_branding_description")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -418,7 +414,7 @@ export default function Settings(props: Props) {
|
|||
</div>
|
||||
<hr className="mt-8" />
|
||||
<div className="py-4 flex justify-end">
|
||||
<Button type="submit">Save</Button>
|
||||
<Button type="submit">{t("save")}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -51,7 +51,6 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||
|
||||
return {
|
||||
props: {
|
||||
localeProp: locale,
|
||||
session,
|
||||
user,
|
||||
...(await serverSideTranslations(locale, ["common"])),
|
||||
|
|
|
@ -8,6 +8,7 @@ import { useEffect, useRef, useState } from "react";
|
|||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { getOrSetUserLocaleFromHeaders } from "@lib/core/i18n/i18n.utils";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import { Member } from "@lib/member";
|
||||
import { Team } from "@lib/team";
|
||||
|
||||
|
@ -20,6 +21,7 @@ import TeamListItem from "@components/team/TeamListItem";
|
|||
import Button from "@components/ui/Button";
|
||||
|
||||
export default function Teams() {
|
||||
const { t } = useLocale();
|
||||
const noop = () => undefined;
|
||||
const [, loading] = useSession();
|
||||
const [teams, setTeams] = useState([]);
|
||||
|
@ -80,7 +82,7 @@ export default function Teams() {
|
|||
};
|
||||
|
||||
return (
|
||||
<Shell heading="Teams" subtitle="Create and manage teams to use collaborative features.">
|
||||
<Shell heading={t("teams")} subtitle={t("create_manage_teams_collaborative")}>
|
||||
<SettingsShell>
|
||||
{!editTeamEnabled && (
|
||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
||||
|
@ -91,10 +93,10 @@ export default function Teams() {
|
|||
<div className="sm:rounded-sm">
|
||||
<div className="pb-5 pr-4 sm:pb-6">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900">
|
||||
Create a team to get started
|
||||
{t("create_team_to_get_started")}
|
||||
</h3>
|
||||
<div className="max-w-xl mt-2 text-sm text-gray-500">
|
||||
<p>Create your first team and invite other users to work together with you.</p>
|
||||
<p>{t("create_first_team_and_invite_others")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,7 +108,7 @@ export default function Teams() {
|
|||
onClick={() => setShowCreateTeamModal(true)}
|
||||
className="btn btn-white">
|
||||
<PlusIcon className="group-hover:text-black text-gray-700 w-3.5 h-3.5 mr-2 inline-block" />
|
||||
New Team
|
||||
{t("new_team")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -156,17 +158,17 @@ export default function Teams() {
|
|||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
Create a new team
|
||||
{t("create_new_team")}
|
||||
</h3>
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">Create a new team to collaborate with users.</p>
|
||||
<p className="text-sm text-gray-400">{t("create_new_team_description")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={createTeam}>
|
||||
<div className="mb-4">
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||
Name
|
||||
{t("name")}
|
||||
</label>
|
||||
<input
|
||||
ref={nameRef}
|
||||
|
@ -180,13 +182,13 @@ export default function Teams() {
|
|||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Create team
|
||||
{t("create_team")}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowCreateTeamModal(false)}
|
||||
type="button"
|
||||
className="mr-2 btn btn-white">
|
||||
Cancel
|
||||
{t("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,4 +1,34 @@
|
|||
{
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"automatically_adjust_theme": "Automatically adjust theme based on invitee preferences",
|
||||
"email": "Email",
|
||||
"full_name": "Full name",
|
||||
"browse_api_documentation": "Browse our API documentation",
|
||||
"leverage_our_api": "Leverage our API for full control and customizability.",
|
||||
"create_webhook": "Create Webhook",
|
||||
"booking_cancelled": "Booking Cancelled",
|
||||
"booking_rescheduled": "Booking Rescheduled",
|
||||
"booking_created": "Booking Created",
|
||||
"event_triggers": "Event triggers",
|
||||
"subscriber_url": "Subscriber Url",
|
||||
"create_new_webhook": "Create a new webhook",
|
||||
"create_new_webhook_to_account": "Create a new webhook to your account",
|
||||
"new_webhook": "New Webhook",
|
||||
"receive_cal_meeting_data": "Receive Cal meeting data at a specified URL, in real-time, when an event is scheduled or cancelled.",
|
||||
"responsive_fullscreen_iframe": "Responsive full screen iframe",
|
||||
"loading": "Loading...",
|
||||
"standard_iframe": "Standard iframe",
|
||||
"iframe_embed": "iframe Embed",
|
||||
"embed_calcom": "The easiest way to embed Cal.com on your website.",
|
||||
"integrate_using_embed_or_webhooks": "Integrate with your website using our embed options, or get real-time booking information using custom webhooks.",
|
||||
"schedule_a_meeting": "Schedule a meeting",
|
||||
"view_and_manage_billing_details": "View and manage your billing details",
|
||||
"view_and_edit_billing_details": "View and edit your billing details, as well as cancel your subscription.",
|
||||
"go_to_billing_portal": "Go to the billing portal",
|
||||
"need_anything_else": "Need anything else?",
|
||||
"further_billing_help": "If you need any further help with billing, our support team are here to help.",
|
||||
"contact_our_support_team": "Contact our support team",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "This user hasn't set up any event types yet.",
|
||||
"edit_logo": "Edit logo",
|
||||
|
@ -147,26 +177,25 @@
|
|||
"new_event_description": "Create a new event type for people to book times with.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} event type created successfully",
|
||||
"hours": "Hours",
|
||||
"full_name": "Full Name",
|
||||
"your_email": "Your Email",
|
||||
"change_avatar": "Change Avatar",
|
||||
"language": "Language",
|
||||
"timezone": "Timezone",
|
||||
"first_day_week": "First day week",
|
||||
"first_day_of_week": "First Day of Week",
|
||||
"single_theme": "Single Theme",
|
||||
"file_not_named": "File is not named [idOrSlug]/[user]",
|
||||
"create_team": "Create Team",
|
||||
"name_team": "Name",
|
||||
"name": "Name",
|
||||
"create_new_team_description": "Create a new team to collaborate with users.",
|
||||
"create_new_team": "Create a new team",
|
||||
"open_invitations": "Open Invitations",
|
||||
"new_team": "New Team",
|
||||
"create_first_invite_other_users": "Create your first team and invite other users to work together with you.",
|
||||
"create_team_get_started": "Create a team to get started",
|
||||
"create_first_team_and_invite_others": "Create your first team and invite other users to work together with you.",
|
||||
"create_team_to_get_started": "Create a team to get started",
|
||||
"teams": "Teams",
|
||||
"create_manage_teams_collaborative": "Create and manage teams to use collaborative features.",
|
||||
"this_feature_only_available_paid_plan": "This feature is only available in paid plan",
|
||||
"order_remove_cal_branding_description": "In order to remove the Cal branding from your booking pages, you need to upgrade to a paid account.",
|
||||
"only_available_on_pro_plan": "This feature is only available in Pro plan",
|
||||
"remove_cal_branding_description": "In order to remove the Cal branding from your booking pages, you need to upgrade to a Pro account.",
|
||||
"to_upgrade_go_to": "To upgrade go to",
|
||||
"edit_profile_info_description": "Edit your profile information, which shows on your scheduling link.",
|
||||
"change_email_contact": "To change your email, please contact",
|
||||
|
@ -174,9 +203,10 @@
|
|||
"profile_updated_successfully": "Profile updated successfully",
|
||||
"your_user_profile_updated_successfully": "Your user profile has been updated successfully.",
|
||||
"user_cannot_found_db": "User seems logged in but cannot be found in the db",
|
||||
"embed_and_webhooks": "Embed & Webhooks",
|
||||
"embed_and_webhooks": "Embed & Webhooks",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"disable": "Disable",
|
||||
"billing": "Billing",
|
||||
"manage_your_billing_info": "Manage your billing information and cancel your subscription.",
|
||||
"availability": "Availability",
|
||||
|
|
Loading…
Reference in a new issue