Cleaned up v1 for app store pages. (#5204)

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Jeroen Reumkens
2022-10-27 05:50:16 +00:00
committed by GitHub
co-authored by Peer Richelsen kodiakhq[bot]
parent 63ce4a68ac
commit d6c4970bf4
18 changed files with 45 additions and 932 deletions
+2 -2
View File
@@ -2,8 +2,8 @@ import { GetStaticPaths, InferGetStaticPropsType } from "next";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
import { getStaticProps } from "@calcom/app-store/_pages/setup/_getStaticProps";
import { AppSetupPage } from "@calcom/app-store/_pages/v2/setup";
export default function SetupInformation(props: InferGetStaticPropsType<typeof getStaticProps>) {
const router = useRouter();
@@ -23,7 +23,7 @@ export default function SetupInformation(props: InferGetStaticPropsType<typeof g
});
}
return <AppSetupPage slug={`${slug}-V2`} {...props} />;
return <AppSetupPage slug={slug} {...props} />;
}
export const getStaticPaths: GetStaticPaths = async () => {
@@ -1,20 +0,0 @@
import { GetStaticPropsContext } from "next";
export const AppSetupPageMap = {
zapier: import("../../../zapier/pages/setup/_getStaticProps"),
};
export const getStaticProps = async (ctx: GetStaticPropsContext) => {
const { slug } = ctx.params || {};
if (typeof slug !== "string") return { notFound: true } as const;
if (!(slug in AppSetupPageMap)) return { props: {} };
const page = await AppSetupPageMap[slug as keyof typeof AppSetupPageMap];
if (!page.getStaticProps) return { props: {} };
const props = await page.getStaticProps(ctx);
return props;
};
@@ -1,19 +0,0 @@
import dynamic from "next/dynamic";
import { DynamicComponent } from "../../../_components/DynamicComponent";
export const AppSetupMap = {
"apple-calendar-V2": dynamic(() => import("../../../applecalendar/pages/v2/setup")),
"exchange-V2": dynamic(() => import("../../../exchangecalendar/pages/v2/setup")),
"exchange2013-calendar-V2": dynamic(() => import("../../../exchange2013calendar/pages/v2/setup")),
"exchange2016-calendar-V2": dynamic(() => import("../../../exchange2016calendar/pages/v2/setup")),
"caldav-calendar-V2": dynamic(() => import("../../../caldavcalendar/pages/v2/setup")),
"zapier-V2": dynamic(() => import("../../../zapier/pages/v2/setup")),
"closecom-V2": dynamic(() => import("../../../closecomothercalendar/pages/v2/setup")),
};
export const AppSetupPage = (props: { slug: string }) => {
return <DynamicComponent<typeof AppSetupMap> componentMap={AppSetupMap} {...props} />;
};
export default AppSetupPage;
@@ -4,9 +4,7 @@ import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Form, TextField } from "@calcom/ui/form/fields";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function AppleCalendarSetup() {
const { t } = useLocale();
@@ -1,101 +0,0 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function AppleCalendarSetup() {
const { t } = useLocale();
const router = useRouter();
const form = useForm({
defaultValues: {
username: "",
password: "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/applecalendar/icon.svg"
alt="Apple Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div>
<h1 className="text-gray-600">{t("connect_apple_server")}</h1>
<div className="mt-1 text-sm">
{t("apple_server_generate_password")}{" "}
<a
className="text-indigo-400"
href="https://appleid.apple.com/account/manage"
target="_blank"
rel="noopener noreferrer">
https://appleid.apple.com/account/manage
</a>
. {t("credentials_stored_encrypted")}
</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/applecalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || t("something_went_wrong"));
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("username")}
label="Apple ID"
placeholder="appleid@domain.com"
/>
<TextField
required
type="password"
{...form.register("password")}
label={t("password")}
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-5 justify-end space-x-2 sm:mt-4 sm:flex">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}
@@ -4,9 +4,7 @@ import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Form, TextField } from "@calcom/ui/form/fields";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function CalDavCalendarSetup() {
const { t } = useLocale();
@@ -1,98 +0,0 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function CalDavCalendarSetup() {
const { t } = useLocale();
const router = useRouter();
const form = useForm({
defaultValues: {
url: "",
username: "",
password: "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/caldavcalendar/icon.svg"
alt="CalDav Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div className="flex w-10/12 flex-col">
<h1 className="text-gray-600">{t("connect_caldav_server")}</h1>
<div className="mt-1 text-sm">{t("credentials_stored_encrypted")}</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/caldavcalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || t("something_went_wrong"));
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("url")}
label={t("calendar_url")}
placeholder="https://example.com/calendar"
/>
<TextField
required
type="text"
{...form.register("username")}
label={t("username")}
placeholder="rickroll"
/>
<TextField
required
type="password"
{...form.register("password")}
label={t("password")}
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-5 justify-end space-x-2 sm:mt-4 sm:flex">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}
@@ -7,9 +7,7 @@ import { Toaster } from "react-hot-toast";
import z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import Button from "@calcom/ui/v2/core/Button";
import { Form, TextField } from "@calcom/ui/v2/core/form/fields";
import showToast from "@calcom/ui/v2/core/notifications";
import { Button, Form, showToast, TextField } from "@calcom/ui/v2";
const formSchema = z.object({
api_key: z.string(),
@@ -1,155 +0,0 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/router";
import { useState, useEffect } from "react";
import { Check, X } from "react-feather";
import { useForm, Controller } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Form, showToast, TextField } from "@calcom/ui/v2";
const formSchema = z.object({
api_key: z.string(),
});
export default function CloseComSetup() {
const { t } = useLocale();
const router = useRouter();
const [testPassed, setTestPassed] = useState<boolean | undefined>(undefined);
const [testLoading, setTestLoading] = useState<boolean>(false);
const form = useForm<{
api_key: string;
}>({
resolver: zodResolver(formSchema),
});
useEffect(() => {
const timer = setTimeout(() => {
if (testPassed === false) {
setTestPassed(undefined);
}
}, 3000);
return () => clearTimeout(timer);
}, [testPassed]);
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[520px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/closecomothercalendar/icon.svg"
alt="Apple Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div>
<h1 className="text-gray-600">{t("provide_api_key")}</h1>
<div className="mt-1 text-sm">
{t("generate_api_key_description")}{" "}
<a
className="text-indigo-400"
href="https://app.close.com/settings/api/"
target="_blank"
rel="noopener noreferrer">
Close.com
</a>
. {t("it_stored_encrypted")}
</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
const res = await fetch("/api/integrations/closecomothercalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (res.ok) {
router.push(json.url);
} else {
showToast(json.message, "error");
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<Controller
name="api_key"
control={form.control}
render={({ field: { onBlur, onChange } }) => (
<TextField
className="my-0"
onBlur={onBlur}
disabled={testPassed === true}
name="api_key"
placeholder="api_xyz..."
onChange={async (e) => {
onChange(e.target.value);
form.setValue("api_key", e.target.value);
await form.trigger("api_key");
}}
/>
)}
/>
</fieldset>
<div className="mt-5 justify-end space-x-2 sm:mt-4 sm:flex">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button
type="submit"
loading={testLoading}
disabled={testPassed === true}
StartIcon={testPassed !== undefined ? (testPassed ? Check : X) : undefined}
className={
testPassed !== undefined
? testPassed
? " !bg-green-100 !text-green-700 hover:bg-green-100"
: "!border-red-700 bg-red-100 !text-red-700 hover:bg-red-100"
: "secondary"
}
color={testPassed === true ? "minimal" : "secondary"}
onClick={async () => {
const check = await form.trigger("api_key");
if (!check) return;
const api_key = form.getValues("api_key");
setTestLoading(true);
const res = await fetch("/api/integrations/closecomothercalendar/check", {
method: "POST",
body: JSON.stringify({ api_key }),
headers: {
"Content-Type": "application/json",
},
});
if (res.status === 200) {
setTestPassed(true);
} else {
setTestPassed(false);
}
setTestLoading(false);
}}>
{t(
testPassed !== undefined ? (testPassed ? "test_passed" : "test_failed") : "test_api_key"
)}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}
@@ -4,9 +4,7 @@ import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Form, TextField } from "@calcom/ui/form/fields";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function Exchange2013CalendarSetup() {
const { t } = useLocale();
@@ -1,95 +0,0 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function Exchange2013CalendarSetup() {
const { t } = useLocale();
const router = useRouter();
const form = useForm({
defaultValues: {
username: "",
password: "",
url: process.env.EXCHANGE_DEFAULT_EWS_URL || "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div>
<img
src="/api/app-store/exchange2013calendar/icon.svg"
alt="Exchange 2013 Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div className="flex w-10/12 flex-col">
<h1 className="text-gray-600">{t("add_exchange2013")}</h1>
<div className="mt-1 text-sm">{t("credentials_stored_encrypted")}</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/exchange2013calendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || t("something_went_wrong"));
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("url")}
label={t("calendar_url")}
placeholder="https://example.com/Ews/Exchange.asmx"
/>
<TextField
required
type="text"
{...form.register("username")}
label="E-Mail"
placeholder="rickroll@example.com"
/>
<TextField
required
type="password"
{...form.register("password")}
label="Password"
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-5 justify-end space-x-2 sm:mt-4 sm:flex">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}
@@ -4,9 +4,7 @@ import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Form, TextField } from "@calcom/ui/form/fields";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function Exchange2016CalendarSetup() {
const { t } = useLocale();
@@ -1,95 +0,0 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert, Button, Form, TextField } from "@calcom/ui/v2";
export default function Exchange2016CalendarSetup() {
const { t } = useLocale();
const router = useRouter();
const form = useForm({
defaultValues: {
username: "",
password: "",
url: process.env.EXCHANGE_DEFAULT_EWS_URL || "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div>
<img
src="/api/app-store/exchange2016calendar/icon.svg"
alt="Exchange 2016 Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div className="flex w-10/12 flex-col">
<h1 className="text-gray-600">{t("add_exchange2016")}</h1>
<div className="mt-1 text-sm">{t("credentials_stored_encrypted")}</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/exchange2016calendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || t("something_went_wrong"));
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("url")}
label={t("calendar_url")}
placeholder="https://example.com/Ews/Exchange.asmx"
/>
<TextField
required
type="text"
{...form.register("username")}
label="E-Mail"
placeholder="rickroll@example.com"
/>
<TextField
required
type="password"
{...form.register("password")}
label="Password"
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-5 justify-end space-x-2 sm:mt-4 sm:flex">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}
@@ -6,9 +6,16 @@ import { Toaster } from "react-hot-toast";
import z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Select, Switch } from "@calcom/ui";
import { Alert } from "@calcom/ui/Alert";
import { EmailField, Form, Label, PasswordField, TextField } from "@calcom/ui/form/fields";
import {
Alert,
Button,
EmailField,
Form,
PasswordField,
TextField,
SelectField,
Switch,
} from "@calcom/ui/v2";
import { ExchangeAuthentication } from "../../enums";
@@ -42,16 +49,16 @@ export default function ExchangeSetup() {
{ value: ExchangeAuthentication.STANDARD, label: t("exchange_authentication_standard") },
{ value: ExchangeAuthentication.NTLM, label: t("exchange_authentication_ntlm") },
];
return (
<>
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div className="flex">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/exchangecalendar/icon.svg"
alt="Microsoft Exchange Calendar"
alt="Microsoft Exchange"
className="h-12 w-12 max-w-2xl"
/>
</div>
@@ -98,24 +105,21 @@ export default function ExchangeSetup() {
label={t("password")}
autoComplete="password"
/>
<div>
<Label>{t("exchange_authentication")}</Label>
<Controller
name="authenticationMethod"
control={form.control}
render={({ field: { onChange } }) => (
<Select
options={authenticationMethods}
defaultValue={authenticationMethods[0]}
className="mt-1"
onChange={async (authentication) => {
onChange(authentication?.value);
form.setValue("authenticationMethod", authentication!.value);
}}
/>
)}
/>
</div>
<Controller
name="authenticationMethod"
control={form.control}
render={({ field: { onChange } }) => (
<SelectField
label={t("exchange_authentication")}
options={authenticationMethods}
defaultValue={authenticationMethods[0]}
onChange={async (authentication) => {
onChange(authentication?.value);
form.setValue("authenticationMethod", authentication!.value);
}}
/>
)}
/>
<Switch
label={t("exchange_compression")}
name="useCompression"
@@ -1,149 +0,0 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/router";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import {
Alert,
Button,
EmailField,
Form,
PasswordField,
TextField,
SelectField,
Switch,
} from "@calcom/ui/v2";
import { ExchangeAuthentication } from "../../../enums";
interface IFormData {
url: string;
username: string;
password: string;
authenticationMethod: ExchangeAuthentication;
useCompression: boolean;
}
const schema = z
.object({
url: z.string().url(),
username: z.string().email(),
password: z.string(),
authenticationMethod: z.number().default(ExchangeAuthentication.STANDARD),
useCompression: z.boolean().default(false),
})
.strict();
export default function ExchangeSetup() {
const { t } = useLocale();
const router = useRouter();
const [errorMessage, setErrorMessage] = useState("");
const form = useForm<IFormData>({
defaultValues: { authenticationMethod: ExchangeAuthentication.STANDARD },
resolver: zodResolver(schema),
});
const authenticationMethods = [
{ value: ExchangeAuthentication.STANDARD, label: t("exchange_authentication_standard") },
{ value: ExchangeAuthentication.NTLM, label: t("exchange_authentication_ntlm") },
];
return (
<>
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/exchangecalendar/icon.svg"
alt="Microsoft Exchange"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div className="grow">
<h1 className="text-gray-600">{t("exchange_add")}</h1>
<div className="text-sm">{t("credentials_stored_encrypted")}</div>
<div className="my-2 mt-5">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/exchangecalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || t("something_went_wrong"));
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-4" disabled={form.formState.isSubmitting}>
<TextField
required
type="url"
{...form.register("url")}
label={t("url")}
placeholder="https://example.com/Ews/Exchange.asmx"
inputMode="url"
/>
<EmailField
required
{...form.register("username")}
label={t("email_address")}
placeholder="john.doe@example.com"
/>
<PasswordField
required
{...form.register("password")}
label={t("password")}
autoComplete="password"
/>
<Controller
name="authenticationMethod"
control={form.control}
render={({ field: { onChange } }) => (
<SelectField
label={t("exchange_authentication")}
options={authenticationMethods}
defaultValue={authenticationMethods[0]}
onChange={async (authentication) => {
onChange(authentication?.value);
form.setValue("authenticationMethod", authentication!.value);
}}
/>
)}
/>
<Switch
label={t("exchange_compression")}
name="useCompression"
onCheckedChange={async (alt) => {
form.setValue("useCompression", alt);
}}
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-4 flex justify-end space-x-2">
<Button type="button" color="secondary" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button type="submit" loading={form.formState.isSubmitting}>
{t("save")}
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
</>
);
}
+10 -13
View File
@@ -1,4 +1,3 @@
import { ClipboardCopyIcon } from "@heroicons/react/solid";
import { Trans } from "next-i18next";
import Link from "next/link";
import { useState } from "react";
@@ -6,8 +5,8 @@ import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, Loader, Tooltip } from "@calcom/ui";
import showToast from "@calcom/ui/v2/core/notifications";
import { ClipboardCopyIcon } from "@calcom/ui/Icon";
import { Button, Loader, showToast, Tooltip } from "@calcom/ui/v2";
export interface IZapierSetupProps {
inviteLink: string;
@@ -19,7 +18,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
const [newApiKey, setNewApiKey] = useState("");
const { t } = useLocale();
const utils = trpc.useContext();
const integrations = trpc.useQuery(["viewer.integrations", { variant: "other" }]);
const integrations = trpc.useQuery(["viewer.integrations", { variant: "automation" }]);
const oldApiKey = trpc.useQuery(["viewer.apiKeys.findKeyOfType", { appId: ZAPIER }]);
const deleteApiKey = trpc.useMutation("viewer.apiKeys.delete");
@@ -42,11 +41,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
}
if (integrations.isLoading) {
return (
<div className="absolute z-50 flex h-screen w-full items-center bg-gray-200">
<Loader />
</div>
);
return <div className="absolute z-50 flex h-screen w-full items-center bg-gray-200" />;
}
return (
@@ -69,16 +64,18 @@ export default function ZapierSetup(props: IZapierSetupProps) {
) : (
<>
<div className="mt-1 text-xl">{t("your_unique_api_key")}</div>
<div className="my-2 mt-3 flex">
<div className="w-full rounded bg-gray-100 py-2 pl-2 pr-5">{newApiKey}</div>
<Tooltip side="top" content="copy">
<div className="my-2 mt-3 flex-wrap sm:flex sm:flex-nowrap">
<code className="h-full w-full whitespace-pre-wrap rounded-md bg-gray-100 py-2 pl-2 pr-2 sm:rounded-r-none sm:pr-5">
{newApiKey}
</code>
<Tooltip side="top" content={t("copy_to_clipboard")}>
<Button
onClick={() => {
navigator.clipboard.writeText(newApiKey);
showToast(t("api_key_copied"), "success");
}}
type="button"
className="rounded-l-none px-4 text-base">
className="mt-4 text-base sm:mt-0 sm:rounded-l-none">
<ClipboardCopyIcon className="mr-2 h-5 w-5 text-neutral-100" />
{t("copy")}
</Button>
@@ -1,20 +0,0 @@
import { GetStaticPropsContext } from "next";
import getAppKeysFromSlug from "../../../../_utils/getAppKeysFromSlug";
export interface IZapierSetupProps {
inviteLink: string;
}
export const getStaticProps = async (ctx: GetStaticPropsContext) => {
if (typeof ctx.params?.slug !== "string") return { notFound: true } as const;
let inviteLink = "";
const appKeys = await getAppKeysFromSlug("zapier");
if (typeof appKeys.invite_link === "string") inviteLink = appKeys.invite_link;
return {
props: {
inviteLink,
},
};
};
@@ -1,126 +0,0 @@
import { Trans } from "next-i18next";
import Link from "next/link";
import { useState } from "react";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { ClipboardCopyIcon } from "@calcom/ui/Icon";
import { Button, Loader, showToast, Tooltip } from "@calcom/ui/v2";
export interface IZapierSetupProps {
inviteLink: string;
}
const ZAPIER = "zapier";
export default function ZapierSetup(props: IZapierSetupProps) {
const [newApiKey, setNewApiKey] = useState("");
const { t } = useLocale();
const utils = trpc.useContext();
const integrations = trpc.useQuery(["viewer.integrations", { variant: "automation" }]);
const oldApiKey = trpc.useQuery(["viewer.apiKeys.findKeyOfType", { appId: ZAPIER }]);
const deleteApiKey = trpc.useMutation("viewer.apiKeys.delete");
const zapierCredentials: { credentialIds: number[] } | undefined = integrations.data?.items.find(
(item: { type: string }) => item.type === "zapier_automation"
);
const [credentialId] = zapierCredentials?.credentialIds || [false];
const showContent = integrations.data && integrations.isSuccess && credentialId;
const isCalDev = process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.dev";
async function createApiKey() {
const event = { note: "Zapier", expiresAt: null, appId: ZAPIER };
const apiKey = await utils.client.mutation("viewer.apiKeys.create", event);
if (oldApiKey.data) {
deleteApiKey.mutate({
id: oldApiKey.data.id,
});
}
setNewApiKey(apiKey);
}
if (integrations.isLoading) {
return <div className="absolute z-50 flex h-screen w-full items-center bg-gray-200" />;
}
return (
<div className="flex h-screen bg-gray-200">
{showContent ? (
<div className="m-auto max-w-[43em] overflow-auto rounded bg-white pb-10 md:p-10">
<div className="md:flex md:flex-row">
<div className="invisible md:visible">
<img className="h-11" src="/api/app-store/zapier/icon.svg" alt="Zapier Logo" />
</div>
<div className="ml-2 mr-2 md:ml-5">
<div className="text-gray-600">{t("setting_up_zapier")}</div>
{!newApiKey ? (
<>
<div className="mt-1 text-xl">{t("generate_api_key")}:</div>
<Button onClick={() => createApiKey()} className="mt-4 mb-4">
{t("generate_api_key")}
</Button>
</>
) : (
<>
<div className="mt-1 text-xl">{t("your_unique_api_key")}</div>
<div className="my-2 mt-3 flex-wrap sm:flex sm:flex-nowrap">
<code className="h-full w-full whitespace-pre-wrap rounded-md bg-gray-100 py-2 pl-2 pr-2 sm:rounded-r-none sm:pr-5">
{newApiKey}
</code>
<Tooltip side="top" content={t("copy_to_clipboard")}>
<Button
onClick={() => {
navigator.clipboard.writeText(newApiKey);
showToast(t("api_key_copied"), "success");
}}
type="button"
className="mt-4 text-base sm:mt-0 sm:rounded-l-none">
<ClipboardCopyIcon className="mr-2 h-5 w-5 text-neutral-100" />
{t("copy")}
</Button>
</Tooltip>
</div>
<div className="mt-2 mb-5 text-sm font-semibold text-gray-600">
{t("copy_safe_api_key")}
</div>
</>
)}
<ol className="mt-5 mb-5 ml-5 mr-5 list-decimal">
{isCalDev && (
<li>
{t("go_to")}
<a href={props.inviteLink} className="text-orange-600 underline">
{t("zapier_invite_link")}
</a>
</li>
)}
<Trans i18nKey="zapier_setup_instructions">
<li>Log into your Zapier account and create a new Zap.</li>
<li>Select Cal.com as your Trigger app. Also choose a Trigger event.</li>
<li>Choose your account and then enter your Unique API Key.</li>
<li>Test your Trigger.</li>
<li>You&apos;re set!</li>
</Trans>
</ol>
<Link href="/apps/installed" passHref={true}>
<Button color="secondary">{t("done")}</Button>
</Link>
</div>
</div>
</div>
) : (
<div className="mt-5 ml-5">
<div>{t("install_zapier_app")}</div>
<div className="mt-3">
<Link href="/apps/zapier" passHref={true}>
<Button>{t("go_to_app_store")}</Button>
</Link>
</div>
</div>
)}
<Toaster position="bottom-right" />
</div>
);
}