parent
55d77993af
commit
f955ccdef9
|
@ -4,40 +4,42 @@ import Link from "next/link";
|
|||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
const links = [
|
||||
{
|
||||
title: "Documentation",
|
||||
description: "Learn how to integrate our tools with your app",
|
||||
icon: DocumentTextIcon,
|
||||
href: "https://docs.cal.com",
|
||||
},
|
||||
{
|
||||
title: "API Reference",
|
||||
description: "A complete API reference for our libraries",
|
||||
icon: CodeIcon,
|
||||
href: "https://api.docs.cal.com",
|
||||
},
|
||||
{
|
||||
title: "Blog",
|
||||
description: "Read our latest news and articles",
|
||||
icon: BookOpenIcon,
|
||||
href: "https://cal.com/blog",
|
||||
},
|
||||
];
|
||||
|
||||
export default function Custom404() {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const username = router.asPath.replace("%20", "-");
|
||||
const links = [
|
||||
{
|
||||
title: t("documentation"),
|
||||
description: t("documentation_description"),
|
||||
icon: DocumentTextIcon,
|
||||
href: "https://docs.cal.com",
|
||||
},
|
||||
{
|
||||
title: t("api_reference"),
|
||||
description: t("api_reference_description"),
|
||||
icon: CodeIcon,
|
||||
href: "https://api.docs.cal.com",
|
||||
},
|
||||
{
|
||||
title: t("blog"),
|
||||
description: t("blog_description"),
|
||||
icon: BookOpenIcon,
|
||||
href: "https://cal.com/blog",
|
||||
},
|
||||
];
|
||||
|
||||
const isEventType404 = router.asPath.includes("/event-types");
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeadSeo
|
||||
title="404: This page could not be found."
|
||||
description="404: This page could not be found."
|
||||
title={t("404_page_not_found")}
|
||||
description={t("404_page_not_found")}
|
||||
nextSeoProps={{
|
||||
nofollow: true,
|
||||
noindex: true,
|
||||
|
@ -48,21 +50,21 @@ export default function Custom404() {
|
|||
<div className="text-center">
|
||||
<p className="text-sm font-semibold text-black uppercase tracking-wide">404 error</p>
|
||||
<h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 tracking-tight sm:text-5xl">
|
||||
This page does not exist.
|
||||
{t("page_doesnt_exist")}
|
||||
</h1>
|
||||
{isEventType404 ? (
|
||||
<span className="inline-block mt-2 text-lg ">
|
||||
Check for spelling mistakes or go back to the previous page.
|
||||
</span>
|
||||
<span className="inline-block mt-2 text-lg ">{t("check_spelling_mistakes_or_go_back")}</span>
|
||||
) : (
|
||||
<a href="https://cal.com/signup" className="inline-block mt-2 text-lg ">
|
||||
The username <strong className="text-blue-500">cal.com{username}</strong> is still available.{" "}
|
||||
<span className="text-blue-500">Register now</span>.
|
||||
{t("the_username")} <strong className="text-blue-500">cal.com{username}</strong>{" "}
|
||||
{t("is_still_available")} <span className="text-blue-500">{t("register_now")}</span>.
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<h2 className="text-sm font-semibold text-gray-500 tracking-wide uppercase">Popular pages</h2>
|
||||
<h2 className="text-sm font-semibold text-gray-500 tracking-wide uppercase">
|
||||
{t("popular_pages")}
|
||||
</h2>
|
||||
{!isEventType404 && (
|
||||
<ul role="list" className="mt-4">
|
||||
<li className="border-2 border-green-500 px-4 py-2">
|
||||
|
@ -77,11 +79,11 @@ export default function Custom404() {
|
|||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
Register <strong className="text-green-500">{username}</strong>
|
||||
{t("register")} <strong className="text-green-500">{username}</strong>
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">Claim your username and schedule events</p>
|
||||
<p className="text-base text-gray-500">{t("claim_username_and_schedule_events")}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
|
@ -146,7 +148,7 @@ export default function Custom404() {
|
|||
Slack
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">Join our community</p>
|
||||
<p className="text-base text-gray-500">{t("join_our_community")}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
|
@ -157,7 +159,8 @@ export default function Custom404() {
|
|||
<div className="mt-8">
|
||||
<Link href="/">
|
||||
<a className="text-base font-medium text-black hover:text-gray-500">
|
||||
Or go back home<span aria-hidden="true"> →</span>
|
||||
{t("or_go_back_home")}
|
||||
<span aria-hidden="true"> →</span>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -2,9 +2,12 @@ import { XIcon } from "@heroicons/react/outline";
|
|||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
export default function Error() {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const { error } = router.query;
|
||||
|
||||
|
@ -14,7 +17,7 @@ export default function Error() {
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<HeadSeo title="Error" description="Error" />
|
||||
<HeadSeo title={t("error")} description={t("error")} />
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
​
|
||||
|
@ -29,16 +32,14 @@ export default function Error() {
|
|||
{error}
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
An error occurred when logging you in. Head back to the login screen and try again.
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">{t("error_during_login")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<Link href="/auth/login">
|
||||
<a className="inline-flex justify-center w-full rounded-sm border border-transparent shadow-sm px-4 py-2 bg-neutral-900 text-base font-medium text-white hover:bg-neutral-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:text-sm">
|
||||
Go back to the login page
|
||||
{t("go_back_login")}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { getCsrfToken } from "next-auth/client";
|
|||
import Link from "next/link";
|
||||
import React, { useMemo } from "react";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import prisma from "@lib/prisma";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
@ -17,6 +18,7 @@ type Props = {
|
|||
};
|
||||
|
||||
export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
||||
const { t } = useLocale();
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [error, setError] = React.useState(null);
|
||||
const [success, setSuccess] = React.useState(false);
|
||||
|
@ -46,7 +48,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
|
||||
return json;
|
||||
} catch (reason) {
|
||||
setError({ message: "An unexpected error occurred. Try again." });
|
||||
setError({ message: t("unexpected_error_try_again") });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
@ -77,14 +79,16 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">Success</h2>
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
{t("success")}
|
||||
</h2>
|
||||
</div>
|
||||
<p>Your password has been reset. You can now login with your newly created password.</p>
|
||||
<p>{t("password_has_been_reset_login")}</p>
|
||||
<Link href="/auth/login">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full flex justify-center py-2 px-4 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
Login
|
||||
{t("login")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -97,18 +101,15 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">Whoops</h2>
|
||||
<h2 className="text-center text-3xl font-extrabold text-gray-900">That Request is Expired.</h2>
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">{t("whoops")}</h2>
|
||||
<h2 className="text-center text-3xl font-extrabold text-gray-900">{t("request_is_expired")}</h2>
|
||||
</div>
|
||||
<p>
|
||||
That request is expired. You can back and enter the email associated with your account and we will
|
||||
you another link to reset your password.
|
||||
</p>
|
||||
<p>{t("request_is_expired_instructions")}</p>
|
||||
<Link href="/auth/forgot-password">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full flex justify-center py-2 px-4 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
Try Again
|
||||
{t("try_again")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -123,7 +124,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<HeadSeo title="Reset Password" description="Change your password" />
|
||||
<HeadSeo title={t("reset_password")} description={t("change_your_password")} />
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6">
|
||||
{isRequestExpired && <Expired />}
|
||||
|
@ -131,16 +132,16 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
Reset Password
|
||||
{t("reset_password")}
|
||||
</h2>
|
||||
<p>Enter the new password you'd like for your account.</p>
|
||||
<p>{t("enter_new_password")}</p>
|
||||
{error && <p className="text-red-600">{error.message}</p>}
|
||||
</div>
|
||||
<form className="space-y-6" onSubmit={handleSubmit} action="#">
|
||||
<input name="csrfToken" type="hidden" defaultValue={csrfToken} hidden />
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
New Password
|
||||
{t("new_password")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
|
@ -181,7 +182,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
)}
|
||||
Submit
|
||||
{t("submit")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,10 +4,12 @@ import Link from "next/link";
|
|||
import React from "react";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
export default function ForgotPassword({ csrfToken }) {
|
||||
const { t } = useLocale();
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [error, setError] = React.useState(null);
|
||||
const [success, setSuccess] = React.useState(false);
|
||||
|
@ -36,7 +38,7 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
|
||||
return json;
|
||||
} catch (reason) {
|
||||
setError({ message: "An unexpected error occurred. Try again." });
|
||||
setError({ message: t("unexpected_error_try_again") });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
@ -65,8 +67,8 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
const Success = () => {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">Done</h2>
|
||||
<p>Check your email. We sent you a link to reset your password.</p>
|
||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">{t("done")}</h2>
|
||||
<p>{t("check_email_reset_password")}</p>
|
||||
{error && <p className="text-red-600">{error.message}</p>}
|
||||
</div>
|
||||
);
|
||||
|
@ -74,7 +76,7 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<HeadSeo title="Forgot Password" description="Forgot Password" />
|
||||
<HeadSeo title={t("forgot_password")} description={t("forgot_password")} />
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="bg-white py-8 px-4 mx-2 shadow rounded-lg sm:px-10 space-y-6">
|
||||
{success && <Success />}
|
||||
|
@ -82,19 +84,16 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
Forgot Password
|
||||
{t("forgot_password")}
|
||||
</h2>
|
||||
<p>
|
||||
Enter the email address associated with your account and we will send you a link to reset
|
||||
your password.
|
||||
</p>
|
||||
<p>{t("reset_instructions")}</p>
|
||||
{error && <p className="text-red-600">{error.message}</p>}
|
||||
</div>
|
||||
<form className="space-y-6" onSubmit={handleSubmit} action="#">
|
||||
<input name="csrfToken" type="hidden" defaultValue={csrfToken} hidden />
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Email address
|
||||
{t("email_address")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
|
@ -137,7 +136,7 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
)}
|
||||
Request Password Reset
|
||||
{t("request_password_reset")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
|
@ -145,7 +144,7 @@ export default function ForgotPassword({ csrfToken }) {
|
|||
<button
|
||||
type="button"
|
||||
className="w-full flex justify-center py-2 px-4 text-sm font-medium text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
Login
|
||||
{t("login")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -4,22 +4,14 @@ import { useRouter } from "next/router";
|
|||
import { useState } from "react";
|
||||
|
||||
import { ErrorCode, getSession } from "@lib/auth";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import AddToHomescreen from "@components/AddToHomescreen";
|
||||
import Loader from "@components/Loader";
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
const errorMessages: { [key: string]: string } = {
|
||||
[ErrorCode.SecondFactorRequired]:
|
||||
"Two-factor authentication enabled. Please enter the six-digit code from your authenticator app.",
|
||||
[ErrorCode.IncorrectPassword]: "Password is incorrect. Please try again.",
|
||||
[ErrorCode.UserNotFound]: "No account exists matching that email address.",
|
||||
[ErrorCode.IncorrectTwoFactorCode]: "Two-factor code is incorrect. Please try again.",
|
||||
[ErrorCode.InternalServerError]:
|
||||
"Something went wrong. Please try again and contact us if the issue persists.",
|
||||
};
|
||||
|
||||
export default function Login({ csrfToken }) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
@ -27,6 +19,13 @@ export default function Login({ csrfToken }) {
|
|||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [secondFactorRequired, setSecondFactorRequired] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const errorMessages: { [key: string]: string } = {
|
||||
[ErrorCode.SecondFactorRequired]: t("2fa_enabled_instructions"),
|
||||
[ErrorCode.IncorrectPassword]: `${t("incorrect_password")} ${t("please_try_again")}`,
|
||||
[ErrorCode.UserNotFound]: t("no_account_exists"),
|
||||
[ErrorCode.IncorrectTwoFactorCode]: `${t("incorrect_2fa_code")} ${t("please_try_again")}`,
|
||||
[ErrorCode.InternalServerError]: `${t("something_went_wrong")} ${t("please_try_again_and_contact_us")}`,
|
||||
};
|
||||
|
||||
const callbackUrl = typeof router.query?.callbackUrl === "string" ? router.query.callbackUrl : "/";
|
||||
|
||||
|
@ -62,18 +61,18 @@ export default function Login({ csrfToken }) {
|
|||
setSecondFactorRequired(true);
|
||||
setErrorMessage(errorMessages[ErrorCode.SecondFactorRequired]);
|
||||
} else {
|
||||
setErrorMessage(errorMessages[response.error] || "Something went wrong.");
|
||||
setErrorMessage(errorMessages[response.error] || t("something_went_wrong"));
|
||||
}
|
||||
setIsSubmitting(false);
|
||||
} catch (e) {
|
||||
setErrorMessage("Something went wrong.");
|
||||
setErrorMessage(t("something_went_wrong"));
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-neutral-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<HeadSeo title="Login" description="Login" />
|
||||
<HeadSeo title={t("login")} description={t("login")} />
|
||||
|
||||
{isSubmitting && (
|
||||
<div className="z-50 absolute w-full h-screen bg-gray-50 flex items-center">
|
||||
|
@ -84,7 +83,7 @@ export default function Login({ csrfToken }) {
|
|||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<img className="h-6 mx-auto" src="/calendso-logo-white-word.svg" alt="Cal.com Logo" />
|
||||
<h2 className="font-cal mt-6 text-center text-3xl font-bold text-neutral-900">
|
||||
Sign in to your account
|
||||
{t("sign_in_account")}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
@ -94,7 +93,7 @@ export default function Login({ csrfToken }) {
|
|||
<input name="csrfToken" type="hidden" defaultValue={csrfToken} hidden />
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-neutral-700">
|
||||
Email address
|
||||
{t("email_address")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
|
@ -115,13 +114,13 @@ export default function Login({ csrfToken }) {
|
|||
<div className="flex">
|
||||
<div className="w-1/2">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-neutral-700">
|
||||
Password
|
||||
{t("password")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="w-1/2 text-right">
|
||||
<Link href="/auth/forgot-password">
|
||||
<a tabIndex={-1} className="font-medium text-primary-600 text-sm">
|
||||
Forgot?
|
||||
{t("forgot")}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -143,7 +142,7 @@ export default function Login({ csrfToken }) {
|
|||
{secondFactorRequired && (
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-neutral-700">
|
||||
Two-Factor Code
|
||||
{t("2fa_code")}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
|
@ -166,7 +165,7 @@ export default function Login({ csrfToken }) {
|
|||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
Sign in
|
||||
{t("sign_in")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -174,9 +173,9 @@ export default function Login({ csrfToken }) {
|
|||
</form>
|
||||
</div>
|
||||
<div className="mt-4 text-neutral-600 text-center text-sm">
|
||||
Don't have an account? {/* replace this with your account creation flow */}
|
||||
{t("dont_have_an_account")} {/* replace this with your account creation flow */}
|
||||
<a href="https://cal.com/signup" className="font-medium text-neutral-900">
|
||||
Create an account
|
||||
{t("create_an_account")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { CheckIcon } from "@heroicons/react/outline";
|
||||
import Link from "next/link";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
export default function Logout() {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed z-50 inset-0 overflow-y-auto"
|
||||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<HeadSeo title="Logged out" description="Logged out" />
|
||||
<HeadSeo title={t("logged_out")} description={t("logged_out")} />
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
​
|
||||
|
@ -22,17 +26,17 @@ export default function Logout() {
|
|||
</div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
You've been logged out
|
||||
{t("youve_been_logged_out")}
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-gray-500">We hope to see you again soon!</p>
|
||||
<p className="text-sm text-gray-500">{t("hope_to_see_you_soon")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<Link href="/auth/login">
|
||||
<a className="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-black text-base font-medium text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black sm:text-sm">
|
||||
Go back to the login page
|
||||
{t("go_back_login")}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { signIn } from "next-auth/client";
|
|||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import prisma from "@lib/prisma";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
@ -9,6 +10,7 @@ import { UsernameInput } from "@components/ui/UsernameInput";
|
|||
import ErrorAlert from "@components/ui/alerts/Error";
|
||||
|
||||
export default function Signup(props) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const [hasErrors, setHasErrors] = useState(false);
|
||||
|
@ -56,9 +58,11 @@ export default function Signup(props) {
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<HeadSeo title="Sign up" description="Sign up" />
|
||||
<HeadSeo title={t("sign_up")} description={t("sign_up")} />
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<h2 className="font-cal text-center text-3xl font-extrabold text-gray-900">Create your account</h2>
|
||||
<h2 className="font-cal text-center text-3xl font-extrabold text-gray-900">
|
||||
{t("create_your_account")}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="bg-white py-8 px-4 shadow mx-2 sm:rounded-lg sm:px-10">
|
||||
|
@ -70,7 +74,7 @@ export default function Signup(props) {
|
|||
</div>
|
||||
<div className="mb-2">
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
||||
Email
|
||||
{t("email")}
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
|
@ -86,7 +90,7 @@ export default function Signup(props) {
|
|||
</div>
|
||||
<div className="mb-2">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
|
||||
Password
|
||||
{t("password")}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
|
@ -99,7 +103,7 @@ export default function Signup(props) {
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="passwordcheck" className="block text-sm font-medium text-gray-700">
|
||||
Confirm password
|
||||
{t("confirm_password")}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
|
@ -114,13 +118,13 @@ export default function Signup(props) {
|
|||
<div className="mt-3 sm:mt-4 flex">
|
||||
<input
|
||||
type="submit"
|
||||
value="Create Account"
|
||||
value={t("create_account")}
|
||||
className="btn btn-primary w-7/12 mr-2 inline-flex justify-center rounded-md border border-transparent cursor-pointer shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black sm:text-sm"
|
||||
/>
|
||||
<a
|
||||
onClick={() => signIn("Cal.com", { callbackUrl: (router.query.callbackUrl || "") as string })}
|
||||
className="w-5/12 inline-flex justify-center text-sm text-gray-500 font-medium border px-4 py-2 rounded btn cursor-pointer">
|
||||
Login instead
|
||||
{t("login_instead")}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -21,6 +21,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|||
import TimezoneSelect from "react-timezone-select";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import AddCalDavIntegration, {
|
||||
ADD_CALDAV_INTEGRATION_FORM_TITLE,
|
||||
} from "@lib/integrations/CalDav/components/AddCalDavIntegration";
|
||||
|
@ -40,25 +41,6 @@ import getEventTypes from "../lib/queries/event-types/get-event-types";
|
|||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
const DEFAULT_EVENT_TYPES = [
|
||||
{
|
||||
title: "15 Min Meeting",
|
||||
slug: "15min",
|
||||
length: 15,
|
||||
},
|
||||
{
|
||||
title: "30 Min Meeting",
|
||||
slug: "30min",
|
||||
length: 30,
|
||||
},
|
||||
{
|
||||
title: "Secret Meeting",
|
||||
slug: "secret",
|
||||
length: 15,
|
||||
hidden: true,
|
||||
},
|
||||
];
|
||||
|
||||
type OnboardingProps = {
|
||||
user: User;
|
||||
integrations?: Record<string, string>[];
|
||||
|
@ -67,8 +49,28 @@ type OnboardingProps = {
|
|||
};
|
||||
|
||||
export default function Onboarding(props: OnboardingProps) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const DEFAULT_EVENT_TYPES = [
|
||||
{
|
||||
title: t("15min_meeting"),
|
||||
slug: "15min",
|
||||
length: 15,
|
||||
},
|
||||
{
|
||||
title: t("30min_meeting"),
|
||||
slug: "30min",
|
||||
length: 30,
|
||||
},
|
||||
{
|
||||
title: t("secret_meeting"),
|
||||
slug: "secret",
|
||||
length: 15,
|
||||
hidden: true,
|
||||
},
|
||||
];
|
||||
|
||||
const [isSubmitting, setSubmitting] = React.useState(false);
|
||||
const [enteredName, setEnteredName] = React.useState();
|
||||
const Sess = useSession();
|
||||
|
@ -159,7 +161,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
</div>
|
||||
<div className="w-2/12 text-right">
|
||||
<Button className="btn-sm" color="secondary" onClick={() => handleAddIntegration(integration.type)}>
|
||||
Connect
|
||||
{t("connect")}
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
|
@ -229,14 +231,11 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
open={isAddCalDavIntegrationDialogOpen}
|
||||
onOpenChange={(isOpen) => setIsAddCalDavIntegrationDialogOpen(isOpen)}>
|
||||
<DialogContent>
|
||||
<DialogHeader
|
||||
title="Connect to CalDav Server"
|
||||
subtitle="Your credentials will be stored and encrypted."
|
||||
/>
|
||||
<DialogHeader title={t("connect_caldav")} subtitle={t("credentials_stored_and_encrypted")} />
|
||||
<div className="my-4">
|
||||
{addCalDavError && (
|
||||
<p className="text-red-700 text-sm">
|
||||
<span className="font-bold">Error: </span>
|
||||
<span className="font-bold">{t("error")}: </span>
|
||||
{addCalDavError.message}
|
||||
</p>
|
||||
)}
|
||||
|
@ -250,14 +249,14 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
type="submit"
|
||||
form={ADD_CALDAV_INTEGRATION_FORM_TITLE}
|
||||
className="flex justify-center py-2 px-4 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
|
||||
Save
|
||||
{t("save")}
|
||||
</button>
|
||||
<DialogClose
|
||||
onClick={() => {
|
||||
setIsAddCalDavIntegrationDialogOpen(false);
|
||||
}}
|
||||
asChild>
|
||||
<Button color="secondary">Cancel</Button>
|
||||
<Button color="secondary">{t("cancel")}</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
@ -367,16 +366,15 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
|
||||
const steps = [
|
||||
{
|
||||
id: "welcome",
|
||||
title: "Welcome to Cal.com",
|
||||
description:
|
||||
"Tell us what to call you and let us know what timezone you’re in. You’ll be able to edit this later.",
|
||||
id: t("welcome"),
|
||||
title: t("welcome_to_calcom"),
|
||||
description: t("welcome_instructions"),
|
||||
Component: (
|
||||
<form className="sm:mx-auto sm:w-full">
|
||||
<section className="space-y-8">
|
||||
<fieldset>
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||
Full name
|
||||
{t("full_name")}
|
||||
</label>
|
||||
<input
|
||||
ref={nameRef}
|
||||
|
@ -384,7 +382,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
name="name"
|
||||
id="name"
|
||||
autoComplete="given-name"
|
||||
placeholder="Your name"
|
||||
placeholder={t("your_name")}
|
||||
defaultValue={props.user.name ?? enteredName}
|
||||
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"
|
||||
|
@ -394,10 +392,10 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
<fieldset>
|
||||
<section className="flex justify-between">
|
||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
||||
Timezone
|
||||
{t("timezone")}
|
||||
</label>
|
||||
<Text variant="caption">
|
||||
Current time:
|
||||
{t("current_time")}:
|
||||
<span className="text-black">{currentTime}</span>
|
||||
</Text>
|
||||
</section>
|
||||
|
@ -412,9 +410,9 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
</form>
|
||||
),
|
||||
hideConfirm: false,
|
||||
confirmText: "Continue",
|
||||
confirmText: t("continue"),
|
||||
showCancel: true,
|
||||
cancelText: "Set up later",
|
||||
cancelText: t("set_up_later"),
|
||||
onComplete: async () => {
|
||||
try {
|
||||
setSubmitting(true);
|
||||
|
@ -432,9 +430,8 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
},
|
||||
{
|
||||
id: "connect-calendar",
|
||||
title: "Connect your calendar",
|
||||
description:
|
||||
"Connect your calendar to automatically check for busy times and new events as they’re scheduled.",
|
||||
title: t("connect_your_calendar"),
|
||||
description: t("connect_your_calendar_instructions"),
|
||||
Component: (
|
||||
<ul className="divide-y divide-gray-200 sm:mx-auto sm:w-full border border-gray-200 rounded-sm">
|
||||
{props.integrations.map((integration) => {
|
||||
|
@ -443,15 +440,14 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
</ul>
|
||||
),
|
||||
hideConfirm: true,
|
||||
confirmText: "Continue",
|
||||
confirmText: t("continue"),
|
||||
showCancel: true,
|
||||
cancelText: "Continue without calendar",
|
||||
cancelText: t("continue_without_calendar"),
|
||||
},
|
||||
{
|
||||
id: "set-availability",
|
||||
title: "Set your availability",
|
||||
description:
|
||||
"Define ranges of time when you are available on a recurring basis. You can create more of these later and assign them to different calendars.",
|
||||
title: t("set_availability"),
|
||||
description: t("set_availability_instructions"),
|
||||
Component: (
|
||||
<>
|
||||
<section className="bg-white dark:bg-opacity-5 text-black dark:text-white mx-auto max-w-lg">
|
||||
|
@ -472,7 +468,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
</section>
|
||||
<footer className="py-6 sm:mx-auto sm:w-full flex flex-col space-y-6">
|
||||
<Button className="justify-center" EndIcon={ArrowRightIcon} type="submit" form={SCHEDULE_FORM_ID}>
|
||||
Continue
|
||||
{t("continue")}
|
||||
</Button>
|
||||
</footer>
|
||||
</>
|
||||
|
@ -482,15 +478,14 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
},
|
||||
{
|
||||
id: "profile",
|
||||
title: "Nearly there",
|
||||
description:
|
||||
"Last thing, a brief description about you and a photo really help you get bookings and let people know who they’re booking with.",
|
||||
title: t("nearly_there"),
|
||||
description: t("nearly_there_instructions"),
|
||||
Component: (
|
||||
<form className="sm:mx-auto sm:w-full" id="ONBOARDING_STEP_4">
|
||||
<section className="space-y-4">
|
||||
<fieldset>
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||
Full name
|
||||
{t("full_name")}
|
||||
</label>
|
||||
<input
|
||||
ref={nameRef}
|
||||
|
@ -498,7 +493,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
name="name"
|
||||
id="name"
|
||||
autoComplete="given-name"
|
||||
placeholder="Your name"
|
||||
placeholder={t("your_name")}
|
||||
defaultValue={props.user.name || enteredName}
|
||||
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"
|
||||
|
@ -506,7 +501,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
</fieldset>
|
||||
<fieldset>
|
||||
<label htmlFor="bio" className="block text-sm font-medium text-gray-700">
|
||||
About
|
||||
{t("about")}
|
||||
</label>
|
||||
<input
|
||||
ref={bioRef}
|
||||
|
@ -518,16 +513,16 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
defaultValue={props.user.bio}
|
||||
/>
|
||||
<Text variant="caption" className="mt-2">
|
||||
A few sentences about yourself. This will appear on your personal url page.
|
||||
{t("few_sentences_about_yourself")}
|
||||
</Text>
|
||||
</fieldset>
|
||||
</section>
|
||||
</form>
|
||||
),
|
||||
hideConfirm: false,
|
||||
confirmText: "Finish",
|
||||
confirmText: t("finish"),
|
||||
showCancel: true,
|
||||
cancelText: "Set up later",
|
||||
cancelText: t("set_up_later"),
|
||||
onComplete: async () => {
|
||||
try {
|
||||
setSubmitting(true);
|
||||
|
@ -557,7 +552,7 @@ export default function Onboarding(props: OnboardingProps) {
|
|||
return (
|
||||
<div className="bg-black min-h-screen">
|
||||
<Head>
|
||||
<title>Cal.com - Getting Started</title>
|
||||
<title>Cal.com - {t("getting_started")}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useEffect, useState } from "react";
|
|||
|
||||
import { asStringOrNull } from "@lib/asStringOrNull";
|
||||
import { getEventName } from "@lib/event";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import useTheme from "@lib/hooks/useTheme";
|
||||
import { isBrandingHidden } from "@lib/isBrandingHidden";
|
||||
import prisma from "@lib/prisma";
|
||||
|
@ -24,6 +25,7 @@ dayjs.extend(toArray);
|
|||
dayjs.extend(timezone);
|
||||
|
||||
export default function Success(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const { location, name, reschedule } = router.query;
|
||||
|
||||
|
@ -71,8 +73,8 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
(isReady && (
|
||||
<div className="h-screen bg-neutral-50 dark:bg-neutral-900">
|
||||
<HeadSeo
|
||||
title={`Booking ${needsConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
description={`Booking ${needsConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
title={needsConfirmation ? t("booking_submitted") : t("booking_confirmed")}
|
||||
description={needsConfirmation ? t("booking_submitted") : t("booking_confirmed")}
|
||||
/>
|
||||
<main className="py-24 mx-auto max-w-3xl">
|
||||
<div className="overflow-y-auto fixed inset-0 z-50">
|
||||
|
@ -95,21 +97,21 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
<h3
|
||||
className="text-2xl font-semibold leading-6 dark:text-white text-neutral-900"
|
||||
id="modal-headline">
|
||||
{needsConfirmation ? "Submitted" : "This meeting is scheduled"}
|
||||
{needsConfirmation ? t("submitted") : t("meeting_is_scheduled")}
|
||||
</h3>
|
||||
<div className="mt-3">
|
||||
<p className="text-sm text-neutral-600 dark:text-gray-300">
|
||||
{needsConfirmation
|
||||
? props.profile.name !== null
|
||||
? `${props.profile.name} still needs to confirm or reject the booking.`
|
||||
: "Your booking still needs to be confirmed or rejected."
|
||||
: `We emailed you and the other attendees a calendar invitation with all the details.`}
|
||||
? t("user_needs_to_confirm_or_reject_booking", { user: props.profile.name })
|
||||
: t("needs_to_be_confirmed_or_rejected")
|
||||
: t("emailed_you_and_attendees")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 py-4 mt-4 text-left text-gray-700 border-t border-b dark:text-gray-300 dark:border-gray-900">
|
||||
<div className="font-medium">What</div>
|
||||
<div className="font-medium">{t("what")}</div>
|
||||
<div className="col-span-2 mb-6">{eventName}</div>
|
||||
<div className="font-medium">When</div>
|
||||
<div className="font-medium">{t("when")}</div>
|
||||
<div className="col-span-2 mb-6">
|
||||
{date.format("dddd, DD MMMM YYYY")}
|
||||
<br />
|
||||
|
@ -120,7 +122,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
</div>
|
||||
{location && (
|
||||
<>
|
||||
<div className="font-medium">Where</div>
|
||||
<div className="font-medium">{t("where")}</div>
|
||||
<div className="col-span-2">{location}</div>
|
||||
</>
|
||||
)}
|
||||
|
@ -130,7 +132,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
{!needsConfirmation && (
|
||||
<div className="flex pt-2 mt-5 text-center sm:mt-0 sm:pt-4">
|
||||
<span className="flex self-center mr-6 font-medium text-gray-700 dark:text-gray-50">
|
||||
Add to calendar
|
||||
{t("add_to_calendar")}
|
||||
</span>
|
||||
<div className="flex">
|
||||
<Link
|
||||
|
@ -217,7 +219,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1000 1000"
|
||||
className="inline-block -mt-1 mr-1 w-4 h-4">
|
||||
<title>Other</title>
|
||||
<title>{t("other")}</title>
|
||||
<path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" />
|
||||
</svg>
|
||||
</a>
|
||||
|
@ -227,7 +229,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
)}
|
||||
{!props.hideBranding && (
|
||||
<div className="pt-4 mt-4 text-xs text-center text-gray-400 border-t dark:border-gray-900 dark:text-white">
|
||||
<a href="https://cal.com/signup">Create your own booking link with Cal.com</a>
|
||||
<a href="https://cal.com/signup">{t("create_booking_link_with_calcom")}</a>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
|
@ -245,7 +247,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
placeholder="rick.astley@cal.com"
|
||||
/>
|
||||
<Button type="submit" className="min-w-max" color="primary">
|
||||
Try it for free
|
||||
{t("try_for_free")}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -263,6 +265,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const typeId = parseInt(asStringOrNull(context.query.type) ?? "");
|
||||
|
||||
if (isNaN(typeId)) {
|
||||
return {
|
||||
notFound: true,
|
||||
|
|
|
@ -1,4 +1,91 @@
|
|||
{
|
||||
"the_username": "The username",
|
||||
"is_still_available": "is still available.",
|
||||
"documentation": "Documentation",
|
||||
"documentation_description": "Learn how to integrate our tools with your app",
|
||||
"api_reference": "API Reference",
|
||||
"api_reference_description": "A complete API reference for our libraries",
|
||||
"blog": "Blog",
|
||||
"blog_description": "Read our latest news and articles",
|
||||
"join_our_community": "Join our community",
|
||||
"claim_username_and_schedule_events": "Claim your username and schedule events",
|
||||
"popular_pages": "Popular pages",
|
||||
"register_now": "Register now",
|
||||
"register": "Register",
|
||||
"page_doesnt_exist": "This page does not exist.",
|
||||
"check_spelling_mistakes_or_go_back": "Check for spelling mistakes or go back to the previous page.",
|
||||
"404_page_not_found": "404: This page could not be found.",
|
||||
"getting_started": "Getting Started",
|
||||
"15min_meeting": "15 Min Meeting",
|
||||
"30min_meeting": "30 Min Meeting",
|
||||
"secret_meeting": "Secret Meeting",
|
||||
"login_instead": "Login instead",
|
||||
"create_account": "Create Account",
|
||||
"confirm_password": "Confirm password",
|
||||
"create_your_account": "Create your account",
|
||||
"sign_up": "Sign up",
|
||||
"youve_been_logged_out": "You've been logged out",
|
||||
"hope_to_see_you_soon": "We hope to see you again soon!",
|
||||
"logged_out": "Logged out",
|
||||
"please_try_again_and_contact_us": "Please try again and contact us if the issue persists.",
|
||||
"incorrect_2fa_code": "Two-factor code is incorrect.",
|
||||
"no_account_exists": "No account exists matching that email address.",
|
||||
"2fa_enabled_instructions": "Two-factor authentication enabled. Please enter the six-digit code from your authenticator app.",
|
||||
"create_an_account": "Create an account",
|
||||
"dont_have_an_account": "Don't have an account?",
|
||||
"2fa_code": "Two-Factor Code",
|
||||
"sign_in_account": "Sign in to your account",
|
||||
"sign_in": "Sign in",
|
||||
"go_back_login": "Go back to the login page",
|
||||
"error_during_login": "An error occurred when logging you in. Head back to the login screen and try again.",
|
||||
"request_password_reset": "Request Password Reset",
|
||||
"forgot_password": "Forgot Password",
|
||||
"forgot": "Forgot?",
|
||||
"done": "Done",
|
||||
"check_email_reset_password": "Check your email. We sent you a link to reset your password.",
|
||||
"finish": "Finish",
|
||||
"few_sentences_about_yourself": "A few sentences about yourself. This will appear on your personal url page.",
|
||||
"nearly_there": "Nearly there",
|
||||
"nearly_there_instructions": "Last thing, a brief description about you and a photo really help you get bookings and let people know who they’re booking with.",
|
||||
"set_availability_instructions": "Define ranges of time when you are available on a recurring basis. You can create more of these later and assign them to different calendars.",
|
||||
"set_availability": "Set your availability",
|
||||
"continue_without_calendar": "Continue without calendar",
|
||||
"connect_your_calendar": "Connect your calendar",
|
||||
"connect_your_calendar_instructions": "Connect your calendar to automatically check for busy times and new events as they’re scheduled.",
|
||||
"set_up_later": "Set up later",
|
||||
"current_time": "Current time",
|
||||
"welcome": "Welcome",
|
||||
"welcome_to_calcom": "Welcome to Cal.com",
|
||||
"welcome_instructions": "Tell us what to call you and let us know what timezone you’re in. You’ll be able to edit this later.",
|
||||
"connect_caldav": "Connect to CalDav Server",
|
||||
"credentials_stored_and_encrypted": "Your credentials will be stored and encrypted.",
|
||||
"connect": "Connect",
|
||||
"try_for_free": "Try it for free",
|
||||
"create_booking_link_with_calcom": "Create your own booking link with Cal.com",
|
||||
"what": "What",
|
||||
"when": "When",
|
||||
"where": "Where",
|
||||
"add_to_calendar": "Add to calendar",
|
||||
"other": "Other",
|
||||
"emailed_you_and_attendees": "We emailed you and the other attendees a calendar invitation with all the details.",
|
||||
"needs_to_be_confirmed_or_rejected": "Your booking still needs to be confirmed or rejected.",
|
||||
"user_needs_to_confirm_or_reject_booking": "{{user}} still needs to confirm or reject the booking.",
|
||||
"meeting_is_scheduled": "This meeting is scheduled",
|
||||
"submitted": "Submitted",
|
||||
"booking_submitted": "Booking Submitted",
|
||||
"booking_confirmed": "Booking Confirmed",
|
||||
"enter_new_password": "Enter the new password you'd like for your account.",
|
||||
"reset_password": "Reset Password",
|
||||
"change_your_password": "Change your password",
|
||||
"try_again": "Try Again",
|
||||
"request_is_expired": "That Request is Expired.",
|
||||
"reset_instructions": "Enter the email address associated with your account and we will send you a link to reset your password.",
|
||||
"request_is_expired_instructions": "That request is expired. Go back and enter the email associated with your account and we will send you another link to reset your password.",
|
||||
"whoops": "Whoops",
|
||||
"login": "Login",
|
||||
"success": "Success",
|
||||
"password_has_been_reset_login": "Your password has been reset. You can now login with your newly created password.",
|
||||
"unexpected_error_try_again": "An unexpected error occurred. Try again.",
|
||||
"back_to_bookings": "Back to bookings",
|
||||
"free_to_pick_another_event_type": "Feel free to pick another event anytime.",
|
||||
"cancelled": "Cancelled",
|
||||
|
@ -10,6 +97,7 @@
|
|||
"error_with_status_code_occured": "An error with status code {{status}} occurred.",
|
||||
"booking_already_cancelled": "This booking was already cancelled",
|
||||
"go_back_home": "Go back home",
|
||||
"or_go_back_home": "Or go back home",
|
||||
"no_meeting_found": "No Meeting Found",
|
||||
"no_meeting_found_description": "This meeting does not exist. Contact the meeting owner for an updated link.",
|
||||
"no_status_bookings_yet": "No {{status}} bookings, yet",
|
||||
|
@ -22,7 +110,6 @@
|
|||
"on": "on",
|
||||
"and": "and",
|
||||
"calendar_shows_busy_between": "Your calendar shows you as busy between",
|
||||
"calendar_no_busy_slots": "Your don't have busy slots in this date.",
|
||||
"troubleshoot": "Troubleshoot",
|
||||
"troubleshoot_description": "Understand why certain times are available and others are blocked.",
|
||||
"overview_of_day": "Here is an overview of your day on",
|
||||
|
@ -91,9 +178,9 @@
|
|||
"password_updated_successfully": "Password updated successfully",
|
||||
"password_has_been_changed": "Your password has been successfully changed.",
|
||||
"error_changing_password": "Error changing password",
|
||||
"something_went_wrong": "Something went wrong",
|
||||
"something_went_wrong": "Something went wrong.",
|
||||
"something_doesnt_look_right": "Something doesn't look right?",
|
||||
"please_try_again": "Please try again",
|
||||
"please_try_again": "Please try again.",
|
||||
"super_secure_new_password": "Your super secure new password",
|
||||
"new_password": "New Password",
|
||||
"your_old_password": "Your old password",
|
||||
|
@ -101,7 +188,7 @@
|
|||
"change_password": "Change Password",
|
||||
"new_password_matches_old_password": "New password matches your old password. Please choose a different password.",
|
||||
"current_incorrect_password": "Current password is incorrect",
|
||||
"incorrect_password": "Password is incorrect",
|
||||
"incorrect_password": "Password is incorrect.",
|
||||
"1_on_1": "1-on-1",
|
||||
"24_h": "24h",
|
||||
"use_setting": "Use setting",
|
||||
|
@ -162,7 +249,7 @@
|
|||
"team_updated_successfully": "Team updated successfully",
|
||||
"your_team_updated_successfully": "Your team has been updated successfully.",
|
||||
"about": "About",
|
||||
"team_description": "A few sentences about your team. This will appear on your team's URL page.",
|
||||
"team_description": "A few sentences about your team. This will appear on your team's URL page.",
|
||||
"members": "Members",
|
||||
"member": "Member",
|
||||
"owner": "Owner",
|
||||
|
|
Loading…
Reference in New Issue