Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b055672ea0 | ||
|
|
e4fbca388c | ||
|
|
2b8bba09c9 | ||
|
|
98cf29f655 | ||
|
|
ae8706316f | ||
|
|
ec8e08d442 | ||
|
|
c33f424333 | ||
|
|
6f2312d1e2 | ||
|
|
c2b6070b7e | ||
|
|
a5bebe2b48 | ||
|
|
e3a1f20cc8 | ||
|
|
ab639591da | ||
|
|
21a9b64eb0 | ||
|
|
636ee7b8a1 | ||
|
|
543e526568 | ||
|
|
e465c1d71d | ||
|
|
cdab9037ce | ||
|
|
21e454d0e2 | ||
|
|
7384f29a1c | ||
|
|
9016a854ca | ||
|
|
446c29dd9c | ||
|
|
2cf1f07d8f | ||
|
|
4f03f8e66d | ||
|
|
e1096620e6 | ||
|
|
d416386d7b | ||
|
|
5b7c55b029 | ||
|
|
9b05311d7f | ||
|
|
313d25d7d8 | ||
|
|
5ec9c41f7c | ||
|
|
d56386d016 | ||
|
|
0968ede733 | ||
|
|
8e3ed28ba9 | ||
|
|
82ea4e9fb7 | ||
|
|
8a440c24c0 | ||
|
|
88a8da3ef6 | ||
|
|
49290fba72 | ||
|
|
a363b1e903 | ||
|
|
7b5e2c8bab | ||
|
|
4b0d22655d | ||
|
|
4f92f60d85 | ||
|
|
6986b5af40 | ||
|
|
e043a5efd8 | ||
|
|
bff28e5d6f | ||
|
|
f10ff18d9f | ||
|
|
cefe4754c7 | ||
|
|
d7aa3c7163 | ||
|
|
e899a92071 | ||
|
|
ebdbe407cd | ||
|
|
e7f917bab9 | ||
|
|
ba9688a04a | ||
|
|
f0e15d77dc | ||
|
|
30b72b687e | ||
|
|
bbf50dbc53 | ||
|
|
bb547a0111 | ||
|
|
1758288948 | ||
|
|
11789c725a | ||
|
|
73bfe0aebe | ||
|
|
24140f0f29 | ||
|
|
e504f5cd9e |
No files matched your search
@@ -0,0 +1,27 @@
|
|||||||
|
name: "Apply issue labels to PR"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
label_on_pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
|
||||||
|
- name: Apply labels from linked issue to PR
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_DATA: ${{ toJson(github.event.pull_request) }}
|
||||||
|
run: node ./.github/workflows/scripts/apply-issue-labels-to-pr.ts
|
||||||
@@ -15,6 +15,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: crowdin action
|
- name: crowdin action
|
||||||
uses: crowdin/github-action@1.5.1
|
uses: crowdin/github-action@1.5.1
|
||||||
@@ -26,6 +28,6 @@ jobs:
|
|||||||
localization_branch_name: main
|
localization_branch_name: main
|
||||||
create_pull_request: false
|
create_pull_request: false
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
const https = require("https");
|
||||||
|
|
||||||
|
async function applyLabelFromLinkedIssueToPR(pr, token) {
|
||||||
|
|
||||||
|
// Get the labels from issues linked to the PR
|
||||||
|
const query = `
|
||||||
|
query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) {
|
||||||
|
repository(owner: $owner, name: $repo) {
|
||||||
|
pullRequest(number: $prNumber) {
|
||||||
|
closingIssuesReferences(first: 10) {
|
||||||
|
nodes {
|
||||||
|
number
|
||||||
|
labels(first: 10) {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const graphqlData = JSON.stringify({
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
owner: pr.base.repo.owner.login,
|
||||||
|
repo: pr.base.repo.name,
|
||||||
|
prNumber: pr.number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
|
hostname: "api.github.com",
|
||||||
|
path: "/graphql",
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Content-Length": graphqlData.length,
|
||||||
|
"Authorization": "Bearer " + token,
|
||||||
|
"User-Agent": "Node.js",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use the native Node.js request library to make the request
|
||||||
|
let linkedIssues;
|
||||||
|
linkedIssues = await new Promise((resolve, reject) => {
|
||||||
|
const request = https.request(requestOptions, (response) => {
|
||||||
|
let responseBody = "";
|
||||||
|
response.on("data", (chunk) => {
|
||||||
|
responseBody += chunk;
|
||||||
|
});
|
||||||
|
response.on("end", () => {
|
||||||
|
resolve(
|
||||||
|
JSON.parse(responseBody)
|
||||||
|
?.data
|
||||||
|
?.repository
|
||||||
|
?.pullRequest
|
||||||
|
?.closingIssuesReferences
|
||||||
|
?.nodes
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
request.on("error", (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
request.write(graphqlData);
|
||||||
|
request.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!linkedIssues || linkedIssues.length === 0) {
|
||||||
|
console.log("No issue linked.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over linked issues and apply labels to PR
|
||||||
|
for (const issue of linkedIssues) {
|
||||||
|
const labels = issue?.labels?.nodes?.map((label) => label.name);
|
||||||
|
|
||||||
|
if (!labels || labels.length === 0) {
|
||||||
|
console.log(`No labels found on the linked issue #${issue.number}.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelsData = JSON.stringify({
|
||||||
|
labels: labels,
|
||||||
|
});
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
|
hostname: "api.github.com",
|
||||||
|
path: `/repos/${pr.base.repo.owner.login}/${pr.base.repo.name}/issues/${pr.number}/labels`,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Content-Length": labelsData.length,
|
||||||
|
"Authorization": "Bearer " + token,
|
||||||
|
"User-Agent": "Node.js",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let labelResult;
|
||||||
|
labelResult = await new Promise((resolve, reject) => {
|
||||||
|
const request = https.request(requestOptions, (response) => {
|
||||||
|
let responseBody = "";
|
||||||
|
response.on("data", (chunk) => {
|
||||||
|
responseBody += chunk;
|
||||||
|
});
|
||||||
|
response.on("data", () => {});
|
||||||
|
response.on("end", () => {
|
||||||
|
resolve(JSON.parse(responseBody));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
request.on("error", (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
request.write(labelsData);
|
||||||
|
request.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (labelResult.message) {
|
||||||
|
console.log(`Error labelling PR: ${labelResult.message}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Applied labels: ${labels.join(", ")} to PR #${
|
||||||
|
pr.number
|
||||||
|
} from linked issue #${issue.number}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the PR data and GitHub token to the script
|
||||||
|
(async () => {
|
||||||
|
if (!process.env.PR_DATA) {
|
||||||
|
console.log("No PR data found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prData = JSON.parse(process.env.PR_DATA);
|
||||||
|
const token = process.env.GITHUB_TOKEN;
|
||||||
|
|
||||||
|
await applyLabelFromLinkedIssueToPR(prData, token);
|
||||||
|
})();
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { ReactElement, ReactNode } from "react";
|
import type { ReactElement, ReactNode } from "react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
import { classNames } from "@calcom/lib";
|
import { classNames } from "@calcom/lib";
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ export function VariantsTable({
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{!isDark && (
|
{!isDark && (
|
||||||
<div data-mode="dark">
|
<div data-mode="dark" className="dark">
|
||||||
<VariantsTable titles={titles} isDark columnMinWidth={columnMinWidth}>
|
<VariantsTable titles={titles} isDark columnMinWidth={columnMinWidth}>
|
||||||
{children}
|
{children}
|
||||||
</VariantsTable>
|
</VariantsTable>
|
||||||
|
|||||||
@@ -193,3 +193,88 @@
|
|||||||
.docs-story {
|
.docs-story {
|
||||||
padding: 24px !important;
|
padding: 24px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer {
|
||||||
|
:root {
|
||||||
|
/* background */
|
||||||
|
|
||||||
|
--cal-bg-emphasis: #E5E7EB;
|
||||||
|
--cal-bg: white;
|
||||||
|
--cal-bg-subtle: #F3F4F6;
|
||||||
|
--cal-bg-muted: #F9FAFB;
|
||||||
|
--cal-bg-inverted: #111827;
|
||||||
|
|
||||||
|
/* background -> components*/
|
||||||
|
--cal-bg-info: #DEE9FC;
|
||||||
|
--cal-bg-success: #E2FBE8;
|
||||||
|
--cal-bg-attention: #FCEED8;
|
||||||
|
--cal-bg-error: #F9E3E2;
|
||||||
|
|
||||||
|
|
||||||
|
/* Borders */
|
||||||
|
--cal-border-emphasis:#9CA3AF;
|
||||||
|
--cal-border: #D1D5DB;
|
||||||
|
--cal-border-subtle:#E5E7EB;
|
||||||
|
--cal-border-muted:#F3F4F6;
|
||||||
|
|
||||||
|
/* Content/Text */
|
||||||
|
--cal-text-emphasis: #111827;
|
||||||
|
--cal-text:#374151;
|
||||||
|
--cal-text-subtle:#6B7280;
|
||||||
|
--cal-text-muted:#9CA3AF;
|
||||||
|
--cal-text-inverted:white;
|
||||||
|
|
||||||
|
/* Content/Text -> components */
|
||||||
|
--cal-text-info:#253985;
|
||||||
|
--cal-text-success:#285231;
|
||||||
|
--cal-text-attention:#73321B;
|
||||||
|
--cal-text-error:#752522;
|
||||||
|
|
||||||
|
/* Brand shinanigans
|
||||||
|
-> These will be computed for the users theme at runtime.
|
||||||
|
*/
|
||||||
|
--cal-brand:#111827;
|
||||||
|
--cal-brand-emphasis:#101010;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
/* background */
|
||||||
|
|
||||||
|
--cal-bg-emphasis: #2B2B2B;
|
||||||
|
--cal-bg: #101010;
|
||||||
|
--cal-bg-subtle: #2B2B2B;
|
||||||
|
--cal-bg-muted: #1C1C1C;
|
||||||
|
--cal-bg-inverted: #F3F4F6;
|
||||||
|
|
||||||
|
/* background -> components*/
|
||||||
|
--cal-bg-info: #DEE9FC;
|
||||||
|
--cal-bg-success: #E2FBE8;
|
||||||
|
--cal-bg-attention: #FCEED8;
|
||||||
|
--cal-bg-error: #F9E3E2;
|
||||||
|
|
||||||
|
|
||||||
|
/* Borders */
|
||||||
|
--cal-border-emphasis: #575757;
|
||||||
|
--cal-border: #444444;
|
||||||
|
--cal-border-subtle: #2B2B2B;
|
||||||
|
--cal-border-muted: #1C1C1C;
|
||||||
|
|
||||||
|
/* Content/Text */
|
||||||
|
--cal-text-emphasis: #F3F4F6;
|
||||||
|
--cal-text: #D6D6D6;
|
||||||
|
--cal-text-subtle: #757575;
|
||||||
|
--cal-text-muted: #575757;
|
||||||
|
--cal-text-inverted: #101010;
|
||||||
|
|
||||||
|
/* Content/Text -> components */
|
||||||
|
--cal-text-info: #253985;
|
||||||
|
--cal-text-success: #285231;
|
||||||
|
--cal-text-attention: #73321B;
|
||||||
|
--cal-text-error: #752522;
|
||||||
|
|
||||||
|
/* Brand shenanigans
|
||||||
|
-> These will be computed for the users theme at runtime.
|
||||||
|
*/
|
||||||
|
--cal-brand: #111827;
|
||||||
|
--cal-brand-emphasis: #101010;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ export default function AddToHomescreen() {
|
|||||||
<path d="M35 40H15c-1.7 0-3-1.3-3-3V19c0-1.7 1.3-3 3-3h7v2h-7c-.6 0-1 .4-1 1v18c0 .6.4 1 1 1h20c.6 0 1-.4 1-1V19c0-.6-.4-1-1-1h-7v-2h7c1.7 0 3 1.3 3 3v18c0 1.7-1.3 3-3 3z" />
|
<path d="M35 40H15c-1.7 0-3-1.3-3-3V19c0-1.7 1.3-3 3-3h7v2h-7c-.6 0-1 .4-1 1v18c0 .6.4 1 1 1h20c.6 0 1-.4 1-1V19c0-.6-.4-1-1-1h-7v-2h7c1.7 0 3 1.3 3 3v18c0 1.7-1.3 3-3 3z" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<p className="text-xs font-medium text-white ltr:ml-3 rtl:mr-3">
|
<p className="text-inverted ms-3 text-xs font-medium">
|
||||||
<span className="inline">{t("add_to_homescreen")}</span>
|
<span className="inline">{t("add_to_homescreen")}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,7 +40,7 @@ export default function AddToHomescreen() {
|
|||||||
type="button"
|
type="button"
|
||||||
className="-mr-1 flex rounded-md p-2 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
className="-mr-1 flex rounded-md p-2 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
||||||
<span className="sr-only">{t("dismiss")}</span>
|
<span className="sr-only">{t("dismiss")}</span>
|
||||||
<FiX className="h-6 w-6 text-white" aria-hidden="true" />
|
<FiX className="text-inverted h-6 w-6" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ export default function AppListCard(props: AppListCardProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${highlight ? "bg-yellow-100" : ""}`}>
|
<div className={`${highlight ? "dark:bg-muted bg-yellow-100" : ""}`}>
|
||||||
<div className="flex gap-x-3 px-5 py-4">
|
<div className="flex gap-x-3 px-5 py-4">
|
||||||
{logo ? <img className="h-10 w-10" src={logo} alt={`${title} logo`} /> : null}
|
{logo ? <img className="h-10 w-10" src={logo} alt={`${title} logo`} /> : null}
|
||||||
<div className="flex grow flex-col gap-y-1 truncate">
|
<div className="flex grow flex-col gap-y-1 truncate">
|
||||||
<div className="flex items-center gap-x-2">
|
<div className="flex items-center gap-x-2">
|
||||||
<h3 className="truncate text-sm font-semibold text-gray-900">{title}</h3>
|
<h3 className="text-emphasis truncate text-sm font-semibold">{title}</h3>
|
||||||
<div className="flex items-center gap-x-2">
|
<div className="flex items-center gap-x-2">
|
||||||
{isDefault && <Badge variant="green">{t("default")}</Badge>}
|
{isDefault && <Badge variant="green">{t("default")}</Badge>}
|
||||||
{isTemplate && <Badge variant="red">Template</Badge>}
|
{isTemplate && <Badge variant="red">Template</Badge>}
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ const tabs = [
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<small className="flex py-4 text-gray-500">
|
<small className="text-subtle flex py-4">
|
||||||
{t("place_where_cal_widget_appear", { appName: APP_NAME })}
|
{t("place_where_cal_widget_appear", { appName: APP_NAME })}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -517,7 +517,7 @@ const tabs = [
|
|||||||
data-testid="embed-code"
|
data-testid="embed-code"
|
||||||
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
|
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
|
||||||
name="embed-code"
|
name="embed-code"
|
||||||
className="h-[calc(100%-50px)] font-mono"
|
className="text-default bg-default selection:bg-subtle h-[calc(100%-50px)] font-mono"
|
||||||
style={{ resize: "none", overflow: "auto" }}
|
style={{ resize: "none", overflow: "auto" }}
|
||||||
readOnly
|
readOnly
|
||||||
value={
|
value={
|
||||||
@@ -534,7 +534,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
|
|||||||
<!-- Cal ${embedType} embed code ends -->`
|
<!-- Cal ${embedType} embed code ends -->`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<p className="hidden text-sm text-gray-500">
|
<p className="text-subtle hidden text-sm">
|
||||||
{t(
|
{t(
|
||||||
"Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options."
|
"Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options."
|
||||||
)}
|
)}
|
||||||
@@ -561,12 +561,12 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<small className="flex py-4 text-gray-500">{t("create_update_react_component")}</small>
|
<small className="text-subtle flex py-4">{t("create_update_react_component")}</small>
|
||||||
<TextArea
|
<TextArea
|
||||||
data-testid="embed-react"
|
data-testid="embed-react"
|
||||||
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
|
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
|
||||||
name="embed-react"
|
name="embed-react"
|
||||||
className="h-[calc(100%-50px)] font-mono"
|
className="text-default bg-default selection:bg-subtle h-[calc(100%-50px)] font-mono"
|
||||||
readOnly
|
readOnly
|
||||||
style={{ resize: "none", overflow: "auto" }}
|
style={{ resize: "none", overflow: "auto" }}
|
||||||
value={`/* First make sure that you have installed the package */
|
value={`/* First make sure that you have installed the package */
|
||||||
@@ -622,7 +622,7 @@ Cal("init", {origin:"${WEBAPP_URL}"});
|
|||||||
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
|
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
|
||||||
return (
|
return (
|
||||||
<components.Control {...props}>
|
<components.Control {...props}>
|
||||||
<FiSun className="ml-2 h-4 w-4 text-gray-500" />
|
<FiSun className="text-subtle ml-2 h-4 w-4" />
|
||||||
{children}
|
{children}
|
||||||
</components.Control>
|
</components.Control>
|
||||||
);
|
);
|
||||||
@@ -634,17 +634,17 @@ const ChooseEmbedTypesDialogContent = () => {
|
|||||||
return (
|
return (
|
||||||
<DialogContent className="rounded-lg p-10" type="creation" size="lg">
|
<DialogContent className="rounded-lg p-10" type="creation" size="lg">
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<h3 className="mb-2 text-2xl font-bold leading-none text-gray-900" id="modal-title">
|
<h3 className="font-cal text-emphasis mb-2 text-2xl font-bold leading-none" id="modal-title">
|
||||||
{t("how_you_want_add_cal_site", { appName: APP_NAME })}
|
{t("how_you_want_add_cal_site", { appName: APP_NAME })}
|
||||||
</h3>
|
</h3>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-500">{t("choose_ways_put_cal_site", { appName: APP_NAME })}</p>
|
<p className="text-subtle text-sm">{t("choose_ways_put_cal_site", { appName: APP_NAME })}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start">
|
<div className="items-start space-y-2 md:flex md:space-y-0">
|
||||||
{embeds.map((embed, index) => (
|
{embeds.map((embed, index) => (
|
||||||
<button
|
<button
|
||||||
className="hover:border-primary-900 w-1/3 rounded-md border border-gray-200 bg-gray-50 p-6 text-left hover:rounded-md hover:bg-gray-100 ltr:mr-4 ltr:last:mr-0 rtl:ml-4 rtl:last:ml-0"
|
className="hover:bg-subtle bg-muted w-full rounded-md border border-transparent p-6 text-left hover:rounded-md ltr:mr-4 ltr:last:mr-0 rtl:ml-4 rtl:last:ml-0 lg:w-1/3"
|
||||||
key={index}
|
key={index}
|
||||||
data-testid={embed.type}
|
data-testid={embed.type}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -652,11 +652,11 @@ const ChooseEmbedTypesDialogContent = () => {
|
|||||||
embedType: embed.type,
|
embedType: embed.type,
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
<div className="order-none box-border flex-none rounded-md border border-solid bg-white">
|
<div className="bg-default order-none box-border flex-none rounded-md border border-solid dark:bg-transparent dark:invert">
|
||||||
{embed.illustration}
|
{embed.illustration}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 font-semibold leading-none text-gray-900">{embed.title}</div>
|
<div className="text-emphasis mt-4 font-semibold">{embed.title}</div>
|
||||||
<p className="mt-2 text-sm text-gray-500">{embed.subtitle}</p>
|
<p className="text-subtle mt-2 text-sm">{embed.subtitle}</p>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -821,9 +821,9 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
enableOverflow
|
enableOverflow
|
||||||
type="creation">
|
type="creation">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex w-1/3 flex-col bg-gray-50 p-8">
|
<div className="bg-muted flex w-1/3 flex-col p-8">
|
||||||
<h3
|
<h3
|
||||||
className="mb-2.5 flex items-center text-xl font-semibold leading-5 text-gray-900"
|
className="text-emphasis mb-2.5 flex items-center text-xl font-semibold leading-5"
|
||||||
id="modal-title">
|
id="modal-title">
|
||||||
<button
|
<button
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
@@ -834,7 +834,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
</button>
|
</button>
|
||||||
{embed.title}
|
{embed.title}
|
||||||
</h3>
|
</h3>
|
||||||
<h4 className="mb-6 text-sm font-normal text-gray-500">{embed.subtitle}</h4>
|
<h4 className="text-emphasis mb-6 text-sm font-normal">{embed.subtitle}</h4>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className={classNames("font-medium", embedType === "element-click" ? "hidden" : "")}>
|
<div className={classNames("font-medium", embedType === "element-click" ? "hidden" : "")}>
|
||||||
<Collapsible
|
<Collapsible
|
||||||
@@ -843,7 +843,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
<CollapsibleContent className="text-sm">
|
<CollapsibleContent className="text-sm">
|
||||||
<div className={classNames(embedType === "inline" ? "block" : "hidden")}>
|
<div className={classNames(embedType === "inline" ? "block" : "hidden")}>
|
||||||
{/*TODO: Add Auto/Fixed toggle from Figma */}
|
{/*TODO: Add Auto/Fixed toggle from Figma */}
|
||||||
<div className="mb-[9px] text-sm">Window sizing</div>
|
<div className="text-default mb-[9px] text-sm">Window sizing</div>
|
||||||
<div className="justify-left flex items-center !font-normal">
|
<div className="justify-left flex items-center !font-normal">
|
||||||
<div className="mr-[9px]">
|
<div className="mr-[9px]">
|
||||||
<TextField
|
<TextField
|
||||||
@@ -893,7 +893,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-4 items-center justify-between",
|
"mt-4 items-center justify-between",
|
||||||
embedType === "floating-popup" ? "" : "hidden"
|
embedType === "floating-popup" ? "text-emphasis" : "hidden"
|
||||||
)}>
|
)}>
|
||||||
<div className="mb-2 text-sm">Button Text</div>
|
<div className="mb-2 text-sm">Button Text</div>
|
||||||
{/* Default Values should come from preview iframe */}
|
{/* Default Values should come from preview iframe */}
|
||||||
@@ -917,7 +917,9 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-4 flex items-center justify-start",
|
"mt-4 flex items-center justify-start",
|
||||||
embedType === "floating-popup" ? "space-x-2 rtl:space-x-reverse" : "hidden"
|
embedType === "floating-popup"
|
||||||
|
? "text-emphasis space-x-2 rtl:space-x-reverse"
|
||||||
|
: "hidden"
|
||||||
)}>
|
)}>
|
||||||
<Switch
|
<Switch
|
||||||
defaultChecked={true}
|
defaultChecked={true}
|
||||||
@@ -933,12 +935,12 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="text-sm">Display Calendar Icon Button</div>
|
<div className="text-default text-sm">Display Calendar Icon Button</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-4 items-center justify-between",
|
"mt-4 items-center justify-between",
|
||||||
embedType === "floating-popup" ? "" : "hidden"
|
embedType === "floating-popup" ? "text-emphasis" : "hidden"
|
||||||
)}>
|
)}>
|
||||||
<div className="mb-2">Position of Button</div>
|
<div className="mb-2">Position of Button</div>
|
||||||
<Select
|
<Select
|
||||||
@@ -957,7 +959,11 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
options={FloatingPopupPositionOptions}
|
options={FloatingPopupPositionOptions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"mt-4",
|
||||||
|
embedType === "floating-popup" ? "text-emphasis" : "hidden"
|
||||||
|
)}>
|
||||||
<div>Button Color</div>
|
<div>Button Color</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
@@ -978,7 +984,11 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"mt-4",
|
||||||
|
embedType === "floating-popup" ? "text-emphasis" : "hidden"
|
||||||
|
)}>
|
||||||
<div>Text Color</div>
|
<div>Text Color</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
@@ -1020,7 +1030,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="text-sm">{t("hide_eventtype_details")}</div>
|
<div className="text-default text-sm">{t("hide_eventtype_details")}</div>
|
||||||
</div>
|
</div>
|
||||||
{[
|
{[
|
||||||
{ name: "brandColor", title: "Brand Color" },
|
{ name: "brandColor", title: "Brand Color" },
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export default function ImageUploader({
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div className="mb-4 sm:flex sm:items-start">
|
<div className="mb-4 sm:flex sm:items-start">
|
||||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
||||||
<h3 className="font-cal text-lg leading-6 text-gray-900" id="modal-title">
|
<h3 className="font-cal text-emphasis text-lg leading-6" id="modal-title">
|
||||||
{t("upload_target", { target })}
|
{t("upload_target", { target })}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -131,9 +131,9 @@ export default function ImageUploader({
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="cropper mt-6 flex flex-col items-center justify-center p-8">
|
<div className="cropper mt-6 flex flex-col items-center justify-center p-8">
|
||||||
{!result && (
|
{!result && (
|
||||||
<div className="flex h-20 max-h-20 w-20 items-center justify-start rounded-full bg-gray-50">
|
<div className="bg-muted flex h-20 max-h-20 w-20 items-center justify-start rounded-full">
|
||||||
{!imageSrc && (
|
{!imageSrc && (
|
||||||
<p className="w-full text-center text-sm text-white sm:text-xs">
|
<p className="text-inverted w-full text-center text-sm sm:text-xs">
|
||||||
{t("no_target", { target })}
|
{t("no_target", { target })}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -144,7 +144,7 @@ export default function ImageUploader({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
|
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
|
||||||
<label className="mt-8 rounded-sm border border-gray-300 bg-white px-3 py-1 text-xs font-medium leading-4 text-gray-700 hover:bg-gray-50 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent dark:text-white dark:hover:bg-gray-900">
|
<label className="border-default bg-default hover:bg-mutedover:text-emphasis dark:hover:bg-inverted text-default dark:text-inverted focus:ring-empthasis mt-8 rounded-sm border px-3 py-1 text-xs font-medium leading-4 focus:outline-none focus:ring-2 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent">
|
||||||
<input
|
<input
|
||||||
onInput={onInputFile}
|
onInput={onInputFile}
|
||||||
type="file"
|
type="file"
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isCurrent
|
isCurrent
|
||||||
? "border-gray-900 text-gray-900"
|
? "text-emphasis border-gray-900"
|
||||||
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
|
: "hover:border-default hover:text-default text-subtle border-transparent",
|
||||||
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium",
|
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
@@ -78,7 +78,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
|
|||||||
{tab.icon && (
|
{tab.icon && (
|
||||||
<tab.icon
|
<tab.icon
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isCurrent ? "text-gray-900" : "text-gray-400 group-hover:text-gray-500",
|
isCurrent ? "text-emphasis" : "group-hover:text-subtle text-muted",
|
||||||
"-ml-0.5 hidden h-4 w-4 ltr:mr-2 rtl:ml-2 sm:inline-block"
|
"-ml-0.5 hidden h-4 w-4 ltr:mr-2 rtl:ml-2 sm:inline-block"
|
||||||
)}
|
)}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -91,7 +91,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const Component = ({
|
|||||||
return (
|
return (
|
||||||
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
|
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
|
||||||
{hasDescriptionItems && (
|
{hasDescriptionItems && (
|
||||||
<div className="align-center mb-4 -ml-4 -mr-4 flex min-h-[450px] w-auto basis-3/5 snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap bg-gray-100 p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:justify-center lg:rounded-md">
|
<div className="align-center bg-subtle mb-4 -ml-4 -mr-4 flex min-h-[450px] w-auto basis-3/5 snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:justify-center lg:rounded-md">
|
||||||
{descriptionItems ? (
|
{descriptionItems ? (
|
||||||
descriptionItems.map((descriptionItem, index) =>
|
descriptionItems.map((descriptionItem, index) =>
|
||||||
typeof descriptionItem === "object" ? (
|
typeof descriptionItem === "object" ? (
|
||||||
@@ -127,13 +127,17 @@ const Component = ({
|
|||||||
<div className="mb-8 flex pt-4">
|
<div className="mb-8 flex pt-4">
|
||||||
<header>
|
<header>
|
||||||
<div className="mb-4 flex items-center">
|
<div className="mb-4 flex items-center">
|
||||||
<img className="min-h-16 min-w-16 h-16 w-16" src={logo} alt={name} />
|
<img
|
||||||
<h1 className="font-cal ml-4 text-3xl text-gray-900">{name}</h1>
|
className={classNames(logo.includes("-dark") && "dark:invert", "min-h-16 min-w-16 h-16 w-16")}
|
||||||
|
src={logo}
|
||||||
|
alt={name}
|
||||||
|
/>
|
||||||
|
<h1 className="font-cal text-emphasis ml-4 text-3xl">{name}</h1>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-sm font-medium text-gray-600">
|
<h2 className="text-default text-sm font-medium">
|
||||||
<Link
|
<Link
|
||||||
href={`categories/${categories[0]}`}
|
href={`categories/${categories[0]}`}
|
||||||
className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">
|
className="bg-subtle text-emphasis rounded-md p-1 text-xs capitalize">
|
||||||
{categories[0]}
|
{categories[0]}
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
• {t("published_by", { author })}
|
• {t("published_by", { author })}
|
||||||
@@ -243,9 +247,11 @@ const Component = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="prose-sm prose mt-8">{body}</div>
|
<div className="prose-sm prose prose-headings:text-emphasis prose-code:text-default prose-strong:text-default text-default mt-8">
|
||||||
<h4 className="mt-8 font-semibold text-gray-900 ">{t("pricing")}</h4>
|
{body}
|
||||||
<span>
|
</div>
|
||||||
|
<h4 className="text-emphasis mt-8 font-semibold ">{t("pricing")}</h4>
|
||||||
|
<span className="text-default">
|
||||||
{price === 0 ? (
|
{price === 0 ? (
|
||||||
t("free_to_use_apps")
|
t("free_to_use_apps")
|
||||||
) : (
|
) : (
|
||||||
@@ -260,16 +266,16 @@ const Component = ({
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h4 className="mt-8 mb-2 font-semibold text-gray-900 ">{t("learn_more")}</h4>
|
<h4 className="text-emphasis mt-8 mb-2 font-semibold ">{t("learn_more")}</h4>
|
||||||
<ul className="prose-sm -ml-1 -mr-1 leading-5">
|
<ul className="prose-sm -ml-1 -mr-1 leading-5">
|
||||||
{docs && (
|
{docs && (
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="text-sm font-normal text-black no-underline hover:underline"
|
className="text-emphasis text-sm font-normal no-underline hover:underline"
|
||||||
href={docs}>
|
href={docs}>
|
||||||
<FiBookOpen className="mr-1 -mt-1 inline h-4 w-4 text-gray-500" />
|
<FiBookOpen className="text-subtle mr-1 -mt-1 inline h-4 w-4" />
|
||||||
{t("documentation")}
|
{t("documentation")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -279,9 +285,9 @@ const Component = ({
|
|||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="font-normal text-black no-underline hover:underline"
|
className="text-emphasis font-normal no-underline hover:underline"
|
||||||
href={website}>
|
href={website}>
|
||||||
<FiExternalLink className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
|
<FiExternalLink className="text-subtle mr-1 -mt-px inline h-4 w-4" />
|
||||||
{website.replace("https://", "")}
|
{website.replace("https://", "")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -291,9 +297,9 @@ const Component = ({
|
|||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="font-normal text-black no-underline hover:underline"
|
className="text-emphasis font-normal no-underline hover:underline"
|
||||||
href={"mailto:" + email}>
|
href={"mailto:" + email}>
|
||||||
<FiMail className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
|
<FiMail className="text-subtle mr-1 -mt-px inline h-4 w-4" />
|
||||||
|
|
||||||
{email}
|
{email}
|
||||||
</a>
|
</a>
|
||||||
@@ -304,9 +310,9 @@ const Component = ({
|
|||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="font-normal text-black no-underline hover:underline"
|
className="text-emphasis font-normal no-underline hover:underline"
|
||||||
href={tos}>
|
href={tos}>
|
||||||
<FiFile className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
|
<FiFile className="text-subtle mr-1 -mt-px inline h-4 w-4" />
|
||||||
{t("terms_of_service")}
|
{t("terms_of_service")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -316,16 +322,16 @@ const Component = ({
|
|||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="font-normal text-black no-underline hover:underline"
|
className="text-emphasis font-normal no-underline hover:underline"
|
||||||
href={privacy}>
|
href={privacy}>
|
||||||
<FiShield className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
|
<FiShield className="text-subtle mr-1 -mt-px inline h-4 w-4" />
|
||||||
{t("privacy_policy")}
|
{t("privacy_policy")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<hr className="my-8" />
|
<hr className="border-subtle my-8 border" />
|
||||||
<span className="leading-1 block text-xs text-gray-500">
|
<span className="leading-1 text-subtle block text-xs">
|
||||||
{t("every_app_published", { appName: APP_NAME, companyName: COMPANY_NAME })}
|
{t("every_app_published", { appName: APP_NAME, companyName: COMPANY_NAME })}
|
||||||
</span>
|
</span>
|
||||||
<a className="mt-2 block text-xs text-red-500" href={`mailto:${SUPPORT_MAIL_ADDRESS}`}>
|
<a className="mt-2 block text-xs text-red-500" href={`mailto:${SUPPORT_MAIL_ADDRESS}`}>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ function CalendarSwitch(props: {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{!!props.destination && (
|
{!!props.destination && (
|
||||||
<span className="ml-8 inline-flex items-center gap-1 rounded-md bg-gray-100 px-2 py-1 text-sm font-normal text-gray-800 sm:ml-4">
|
<span className="bg-subtle text-default ml-8 inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm font-normal sm:ml-4">
|
||||||
<FiArrowLeft className="h-4 w-4" />
|
<FiArrowLeft className="h-4 w-4" />
|
||||||
{t("adding_events_to")}
|
{t("adding_events_to")}
|
||||||
</span>
|
</span>
|
||||||
@@ -177,14 +177,14 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
credentialId={item.credentialId}
|
credentialId={item.credentialId}
|
||||||
trashIcon
|
trashIcon
|
||||||
onSuccess={props.onChanged}
|
onSuccess={props.onChanged}
|
||||||
buttonProps={{ className: "border border-gray-300" }}
|
buttonProps={{ className: "border border-default" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}>
|
}>
|
||||||
<div className="border-t border-gray-200">
|
<div className="border-subtle border-t">
|
||||||
{!fromOnboarding && (
|
{!fromOnboarding && (
|
||||||
<>
|
<>
|
||||||
<p className="px-5 pt-4 text-sm text-gray-500">{t("toggle_calendars_conflict")}</p>
|
<p className="text-subtle px-5 pt-4 text-sm">{t("toggle_calendars_conflict")}</p>
|
||||||
<ul className="space-y-2 px-5 py-4">
|
<ul className="space-y-2 px-5 py-4">
|
||||||
{item.calendars.map((cal) => (
|
{item.calendars.map((cal) => (
|
||||||
<CalendarSwitch
|
<CalendarSwitch
|
||||||
@@ -218,7 +218,7 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
credentialId={item.credentialId}
|
credentialId={item.credentialId}
|
||||||
trashIcon
|
trashIcon
|
||||||
onSuccess={props.onChanged}
|
onSuccess={props.onChanged}
|
||||||
buttonProps={{ className: "border border-gray-300" }}
|
buttonProps={{ className: "border border-default" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -279,18 +279,18 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between rounded-md border border-gray-200 bg-gray-50 p-4">
|
<div className="bg-muted border-subtle flex justify-between rounded-md border p-4">
|
||||||
<div className="flex w-full flex-col items-start gap-4 md:flex-row md:items-center">
|
<div className="flex w-full flex-col items-start gap-4 md:flex-row md:items-center">
|
||||||
<div className="relative rounded-md border border-gray-200 bg-white p-1.5">
|
<div className="bg-default border-subtle relative rounded-md border p-1.5">
|
||||||
<FiCalendar className="h-8 w-8" strokeWidth="1" />
|
<FiCalendar className="text-default h-8 w-8" strokeWidth="1" />
|
||||||
<FiPlus
|
<FiPlus
|
||||||
className="absolute left-4 top-1/2 ml-0.5 mt-[1px] h-2 w-2 text-black"
|
className="text-emphasis absolute left-4 top-1/2 ml-0.5 mt-[1px] h-2 w-2"
|
||||||
strokeWidth="4"
|
strokeWidth="4"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:w-6/12">
|
<div className="md:w-6/12">
|
||||||
<h1 className="text-sm font-semibold">{t("create_events_on")}</h1>
|
<h1 className="text-emphasis text-sm font-semibold">{t("create_events_on")}</h1>
|
||||||
<p className="text-sm font-normal">{t("set_calendar")}</p>
|
<p className="text-default text-sm font-normal">{t("set_calendar")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="justify-end md:w-6/12">
|
<div className="justify-end md:w-6/12">
|
||||||
<DestinationCalendarSelector
|
<DestinationCalendarSelector
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function TwoFactor({ center = true }) {
|
|||||||
<div className={center ? "mx-auto !mt-0 max-w-sm" : "!mt-0 max-w-sm"}>
|
<div className={center ? "mx-auto !mt-0 max-w-sm" : "!mt-0 max-w-sm"}>
|
||||||
<Label className="mt-4"> {t("2fa_code")}</Label>
|
<Label className="mt-4"> {t("2fa_code")}</Label>
|
||||||
|
|
||||||
<p className="mb-4 text-sm text-gray-500">{t("2fa_enabled_instructions")}</p>
|
<p className="text-subtle mb-4 text-sm">{t("2fa_enabled_instructions")}</p>
|
||||||
<input hidden type="hidden" value={value} {...methods.register("totpCode")} />
|
<input hidden type="hidden" value={value} {...methods.register("totpCode")} />
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function AdminLayout({
|
|||||||
const isAppsPage = router.asPath.startsWith("/settings/admin/apps");
|
const isAppsPage = router.asPath.startsWith("/settings/admin/apps");
|
||||||
return (
|
return (
|
||||||
<SettingsLayout {...rest}>
|
<SettingsLayout {...rest}>
|
||||||
<div className="mx-auto flex max-w-4xl flex-row divide-y divide-gray-200">
|
<div className="divide-subtle mx-auto flex max-w-4xl flex-row divide-y">
|
||||||
<div className={isAppsPage ? "min-w-0" : "flex flex-1 [&>*]:flex-1"}>
|
<div className={isAppsPage ? "min-w-0" : "flex flex-1 [&>*]:flex-1"}>
|
||||||
<ErrorBoundary>{children}</ErrorBoundary>
|
<ErrorBoundary>{children}</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import classNames from "@lib/classNames";
|
|||||||
|
|
||||||
function SkeletonLoader() {
|
function SkeletonLoader() {
|
||||||
return (
|
return (
|
||||||
<ul className="animate-pulse divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
|
<ul className="divide-subtle border-subtle bg-default animate-pulse divide-y rounded-md border sm:mx-0 sm:overflow-hidden">
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
@@ -20,8 +20,8 @@ export default SkeletonLoader;
|
|||||||
function SkeletonItem() {
|
function SkeletonItem() {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<div className="flex items-center justify-between py-5 hover:bg-neutral-50 ltr:pl-4 rtl:pr-4 sm:ltr:pl-0 sm:rtl:pr-0">
|
<div className="flex items-center justify-between py-5 ltr:pl-4 rtl:pr-4 sm:ltr:pl-0 sm:rtl:pr-0">
|
||||||
<div className="items-between flex w-full flex-col justify-center hover:bg-neutral-50 sm:px-6">
|
<div className="items-between flex w-full flex-col justify-center sm:px-6">
|
||||||
<SkeletonText className="my-1 h-4 w-32" />
|
<SkeletonText className="my-1 h-4 w-32" />
|
||||||
<SkeletonText className="my-1 h-2 w-24" />
|
<SkeletonText className="my-1 h-2 w-24" />
|
||||||
<SkeletonText className="my-1 h-2 w-40" />
|
<SkeletonText className="my-1 h-2 w-40" />
|
||||||
@@ -43,7 +43,7 @@ export const SelectSkeletonLoader = ({ className }: { className?: string }) => {
|
|||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3",
|
"border-subtle group flex w-full items-center justify-between rounded-sm border px-[10px] py-3",
|
||||||
className
|
className
|
||||||
)}>
|
)}>
|
||||||
<div className="flex-grow truncate text-sm">
|
<div className="flex-grow truncate text-sm">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
|||||||
return (
|
return (
|
||||||
<div key={`${location.type}-${index}`} className="flex flex-row items-center text-sm font-medium">
|
<div key={`${location.type}-${index}`} className="flex flex-row items-center text-sm font-medium">
|
||||||
{eventLocationType.iconUrl === "/link.svg" ? (
|
{eventLocationType.iconUrl === "/link.svg" ? (
|
||||||
<FiLink className="dark:text-darkgray-600 min-h-4 min-w-4 ml-[2px] opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 " />
|
<FiLink className="text-default min-h-4 min-w-4 ml-[2px] opacity-70 ltr:mr-[10px] rtl:ml-[10px] " />
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
src={eventLocationType.iconUrl}
|
src={eventLocationType.iconUrl}
|
||||||
@@ -61,7 +61,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
|||||||
|
|
||||||
const filteredLocations = renderLocations.filter(excludeNullValues) as JSX.Element[];
|
const filteredLocations = renderLocations.filter(excludeNullValues) as JSX.Element[];
|
||||||
return filteredLocations.length ? (
|
return filteredLocations.length ? (
|
||||||
<div className="dark:text-darkgray-600 mr-6 flex w-full flex-col space-y-4 break-words text-sm text-gray-600">
|
<div className="text-default mr-6 flex w-full flex-col space-y-4 break-words text-sm">
|
||||||
{filteredLocations}
|
{filteredLocations}
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div ref={slotPickerRef}>
|
<div ref={slotPickerRef}>
|
||||||
{!!date ? (
|
{!!date ? (
|
||||||
<div className="dark:bg-darkgray-100 mt-8 flex h-full w-full flex-col rounded-md px-4 text-center sm:mt-0 sm:p-4 md:-mb-5 md:min-w-[200px] md:p-4 lg:min-w-[300px]">
|
<div className="mt-8 flex h-full w-full flex-col rounded-md px-4 text-center sm:mt-0 sm:p-4 md:-mb-5 md:min-w-[200px] md:p-4 lg:min-w-[300px]">
|
||||||
<div className="mb-4 flex items-center text-left text-base">
|
<div className="mb-4 flex items-center text-left text-base">
|
||||||
<div className="mr-4">
|
<div className="mr-4">
|
||||||
<span className="text-bookingdarker dark:text-darkgray-800 font-semibold text-gray-900">
|
<span className="text-emphasis font-semibold">
|
||||||
{nameOfDay(i18n.language, Number(date.format("d")), "short")}
|
{nameOfDay(i18n.language, Number(date.format("d")), "short")}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-bookinglight">
|
<span className="text-subtle">
|
||||||
, {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
|
, {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,7 +132,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||||||
{seatsPerTimeSlot && slot.attendees && (slotFull || notEnoughSeats) ? (
|
{seatsPerTimeSlot && slot.attendees && (slotFull || notEnoughSeats) ? (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"text-primary-500 dark:bg-darkgray-200 dark:text-darkgray-900 mb-2 block rounded-sm border bg-white py-2 font-medium opacity-25 dark:border-transparent ",
|
"text-default bg-default border-subtle mb-2 block rounded-sm border py-2 font-medium opacity-25",
|
||||||
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
||||||
)}>
|
)}>
|
||||||
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
|
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
|
||||||
@@ -147,8 +147,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||||||
href={bookingUrl}
|
href={bookingUrl}
|
||||||
prefetch={false}
|
prefetch={false}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"hover:bg-brand hover:border-brand hover:text-brandcontrast dark:hover:text-darkmodebrandcontrast",
|
" bg-default dark:bg-muted border-default hover:bg-subtle hover:border-brand-default text-emphasis mb-2 block rounded-md border py-2 text-sm font-medium",
|
||||||
"dark:bg-darkgray-200 dark:hover:bg-darkmodebrand dark:hover:border-darkmodebrand dark:text-darkgray-800 mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent",
|
|
||||||
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
||||||
)}
|
)}
|
||||||
data-testid="time">
|
data-testid="time">
|
||||||
@@ -174,7 +173,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||||||
|
|
||||||
{!isLoading && !slots.length && (
|
{!isLoading && !slots.length && (
|
||||||
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
|
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
|
||||||
<h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
|
<h1 className="text-emphasis my-6 text-xl">{t("all_booked_today")}</h1>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -83,30 +83,25 @@ const BookingDescription: FC<Props> = (props) => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
truncateAfter={3}
|
truncateAfter={3}
|
||||||
/>
|
/>
|
||||||
<h2 className="mt-1 mb-2 break-words text-sm font-medium text-gray-600 dark:text-gray-300">
|
<h2 className="text-default mt-1 mb-2 break-words text-sm font-medium ">{profile.name}</h2>
|
||||||
{profile.name}
|
<h1 className="font-cal text-emphasis mb-6 break-words text-2xl font-semibold leading-none">
|
||||||
</h2>
|
|
||||||
<h1 className="font-cal dark:text-darkgray-900 mb-6 break-words text-2xl font-semibold leading-none text-gray-900">
|
|
||||||
{eventType.title}
|
{eventType.title}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="dark:text-darkgray-600 flex flex-col space-y-4 text-sm font-medium text-gray-600">
|
<div className=" text-default flex flex-col space-y-4 text-sm font-medium">
|
||||||
{eventType?.description && (
|
{eventType?.description && (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"scroll-bar scrollbar-track-w-20 -mx-5 flex max-h-[180px] overflow-y-scroll px-5 ",
|
"scroll-bar scrollbar-track-w-20 -mx-5 flex max-h-[180px] overflow-y-scroll px-5 ",
|
||||||
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
|
isBookingPage && "text-default text-sm font-medium"
|
||||||
)}>
|
)}>
|
||||||
|
{/* TODO: Fix colors when token is introdcued to DS */}
|
||||||
<div className="max-w-full flex-shrink break-words [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600">
|
<div className="max-w-full flex-shrink break-words [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600">
|
||||||
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{requiresConfirmation && (
|
{requiresConfirmation && (
|
||||||
<div
|
<div className={classNames("items-top flex", isBookingPage && "text-default text-sm font-medium")}>
|
||||||
className={classNames(
|
|
||||||
"items-top flex",
|
|
||||||
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
|
|
||||||
)}>
|
|
||||||
<div>
|
<div>
|
||||||
<FiCheckSquare className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
|
<FiCheckSquare className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
|
||||||
</div>
|
</div>
|
||||||
@@ -119,7 +114,7 @@ const BookingDescription: FC<Props> = (props) => {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"flex flex-nowrap text-sm font-medium",
|
"flex flex-nowrap text-sm font-medium",
|
||||||
isBookingPage && "dark:text-darkgray-600 text-gray-600",
|
isBookingPage && "text-default",
|
||||||
!eventType.metadata?.multipleDuration && "items-center"
|
!eventType.metadata?.multipleDuration && "items-center"
|
||||||
)}>
|
)}>
|
||||||
<FiClock
|
<FiClock
|
||||||
@@ -137,9 +132,9 @@ const BookingDescription: FC<Props> = (props) => {
|
|||||||
variant="gray"
|
variant="gray"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
duration === dur.toString()
|
duration === dur.toString()
|
||||||
? "bg-darkgray-200 text-darkgray-900 dark:bg-darkmodebrand dark:!text-darkmodebrandcontrast"
|
? "bg-emphasis border-emphasis text-emphasis "
|
||||||
: "hover:bg-darkgray-200 dark:hover:bg-darkmodebrand hover:text-darkgray-900 dark:hover:text-darkmodebrandcontrast dark:bg-darkgray-200 bg-gray-200 text-gray-900 dark:text-white",
|
: "bg-subtle text-default border-transparent ",
|
||||||
"cursor-pointer"
|
"cursor-pointer border"
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDuration(dur);
|
setDuration(dur);
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
{t("rejection_reason")}
|
{t("rejection_reason")}
|
||||||
<span className="font-normal text-gray-500"> (Optional)</span>
|
<span className="text-subtle font-normal"> (Optional)</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
value={rejectionReason}
|
value={rejectionReason}
|
||||||
@@ -292,13 +292,13 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<tr className="group flex flex-col hover:bg-gray-50 sm:flex-row">
|
<tr className="hover:bg-muted group flex flex-col sm:flex-row">
|
||||||
<td
|
<td
|
||||||
className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[12rem]"
|
className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[12rem]"
|
||||||
onClick={onClickTableData}>
|
onClick={onClickTableData}>
|
||||||
<div className="cursor-pointer py-4">
|
<div className="cursor-pointer py-4">
|
||||||
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
<div className="text-emphasis text-sm leading-6">{startTime}</div>
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-subtle text-sm">
|
||||||
{formatTime(booking.startTime, user?.timeFormat, user?.timeZone)} -{" "}
|
{formatTime(booking.startTime, user?.timeFormat, user?.timeZone)} -{" "}
|
||||||
{formatTime(booking.endTime, user?.timeFormat, user?.timeZone)}
|
{formatTime(booking.endTime, user?.timeFormat, user?.timeZone)}
|
||||||
<MeetingTimeInTimezones
|
<MeetingTimeInTimezones
|
||||||
@@ -325,7 +325,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{recurringDates !== undefined && (
|
{recurringDates !== undefined && (
|
||||||
<div className="mt-2 text-sm text-gray-400">
|
<div className="text-muted mt-2 text-sm">
|
||||||
<RecurringBookingsTooltip booking={booking} recurringDates={recurringDates} />
|
<RecurringBookingsTooltip booking={booking} recurringDates={recurringDates} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -335,8 +335,8 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
{/* Time and Badges for mobile */}
|
{/* Time and Badges for mobile */}
|
||||||
<div className="w-full pt-4 pb-2 sm:hidden">
|
<div className="w-full pt-4 pb-2 sm:hidden">
|
||||||
<div className="flex w-full items-center justify-between sm:hidden">
|
<div className="flex w-full items-center justify-between sm:hidden">
|
||||||
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
<div className="text-emphasis text-sm leading-6">{startTime}</div>
|
||||||
<div className="pr-2 text-sm text-gray-500">
|
<div className="text-subtle pr-2 text-sm">
|
||||||
{formatTime(booking.startTime, user?.timeFormat, user?.timeZone)} -{" "}
|
{formatTime(booking.startTime, user?.timeFormat, user?.timeZone)} -{" "}
|
||||||
{formatTime(booking.endTime, user?.timeFormat, user?.timeZone)}
|
{formatTime(booking.endTime, user?.timeFormat, user?.timeZone)}
|
||||||
<MeetingTimeInTimezones
|
<MeetingTimeInTimezones
|
||||||
@@ -365,7 +365,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{recurringDates !== undefined && (
|
{recurringDates !== undefined && (
|
||||||
<div className="text-sm text-gray-400 sm:hidden">
|
<div className="text-muted text-sm sm:hidden">
|
||||||
<RecurringBookingsTooltip booking={booking} recurringDates={recurringDates} />
|
<RecurringBookingsTooltip booking={booking} recurringDates={recurringDates} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -375,21 +375,21 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
<div
|
<div
|
||||||
title={title}
|
title={title}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-gray-900 md:max-w-full",
|
"max-w-10/12 sm:max-w-56 text-emphasis text-sm font-medium leading-6 md:max-w-full",
|
||||||
isCancelled ? "line-through" : ""
|
isCancelled ? "line-through" : ""
|
||||||
)}>
|
)}>
|
||||||
{title}
|
{title}
|
||||||
<span> </span>
|
<span> </span>
|
||||||
|
|
||||||
{!!booking?.eventType?.price && !booking.paid && (
|
{!!booking?.eventType?.price && !booking.paid && (
|
||||||
<Badge className="hidden ltr:ml-2 ltr:mr-2 rtl:ml-2 sm:inline-flex" variant="orange">
|
<Badge className="ms-2 me-2 hidden sm:inline-flex" variant="orange">
|
||||||
{t("pending_payment")}
|
{t("pending_payment")}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{booking.description && (
|
{booking.description && (
|
||||||
<div
|
<div
|
||||||
className="max-w-10/12 sm:max-w-32 md:max-w-52 xl:max-w-80 truncate text-sm text-gray-600"
|
className="max-w-10/12 sm:max-w-32 md:max-w-52 xl:max-w-80 text-default truncate text-sm"
|
||||||
title={booking.description}>
|
title={booking.description}>
|
||||||
"{booking.description}"
|
"{booking.description}"
|
||||||
</div>
|
</div>
|
||||||
@@ -413,7 +413,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
<>
|
<>
|
||||||
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
|
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
|
||||||
{isConfirmed && <TableActions actions={bookedActions} />}
|
{isConfirmed && <TableActions actions={bookedActions} />}
|
||||||
{isRejected && <div className="text-sm text-gray-500">{t("rejected")}</div>}
|
{isRejected && <div className="text-subtle text-sm">{t("rejected")}</div>}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||||
@@ -475,10 +475,10 @@ const RecurringBookingsTooltip = ({ booking, recurringDates }: RecurringBookings
|
|||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
})}>
|
})}>
|
||||||
<div className="text-gray-600 dark:text-white">
|
<div className="text-default">
|
||||||
<FiRefreshCcw
|
<FiRefreshCcw
|
||||||
strokeWidth="3"
|
strokeWidth="3"
|
||||||
className="float-left mr-1 mt-1.5 inline-block h-3 w-3 text-gray-400"
|
className="text-muted float-left mr-1 mt-1.5 inline-block h-3 w-3"
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 pl-5 text-xs">
|
<p className="mt-1 pl-5 text-xs">
|
||||||
{booking.status === BookingStatus.ACCEPTED
|
{booking.status === BookingStatus.ACCEPTED
|
||||||
@@ -551,13 +551,13 @@ const DisplayAttendees = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div className="text-sm text-gray-900">
|
<div className="text-emphasis text-sm">
|
||||||
{user && <FirstAttendee user={user} currentEmail={currentEmail} />}
|
{user && <FirstAttendee user={user} currentEmail={currentEmail} />}
|
||||||
{attendees.length > 1 ? <span>, </span> : <span> {t("and")} </span>}
|
{attendees.length > 1 ? <span>, </span> : <span> {t("and")} </span>}
|
||||||
<Attendee {...attendees[0]} />
|
<Attendee {...attendees[0]} />
|
||||||
{attendees.length > 1 && (
|
{attendees.length > 1 && (
|
||||||
<>
|
<>
|
||||||
<div className="inline-block text-sm text-gray-900"> {t("and")} </div>
|
<div className="text-emphasis inline-block text-sm"> {t("and")} </div>
|
||||||
{attendees.length > 2 ? (
|
{attendees.length > 2 ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={attendees.slice(1).map((attendee) => (
|
content={attendees.slice(1).map((attendee) => (
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ export default function CancelBooking(props: Props) {
|
|||||||
<>
|
<>
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
|
<div className="bg-error mx-auto flex h-12 w-12 items-center justify-center rounded-full">
|
||||||
<FiX className="h-6 w-6 text-red-600" />
|
<FiX className="h-6 w-6 text-red-600" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-center sm:mt-5">
|
<div className="mt-3 text-center sm:mt-5">
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
<h3 className="text-emphasis text-lg font-medium leading-6" id="modal-title">
|
||||||
{error}
|
{error}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,13 +59,13 @@ export default function CancelBooking(props: Props) {
|
|||||||
)}
|
)}
|
||||||
{!error && (
|
{!error && (
|
||||||
<div className="mt-5 sm:mt-6">
|
<div className="mt-5 sm:mt-6">
|
||||||
<label className="text-bookingdark font-medium dark:text-white">{t("cancellation_reason")}</label>
|
<label className="text-default font-medium">{t("cancellation_reason")}</label>
|
||||||
<TextArea
|
<TextArea
|
||||||
ref={cancelBookingRef}
|
ref={cancelBookingRef}
|
||||||
placeholder={t("cancellation_reason_placeholder")}
|
placeholder={t("cancellation_reason_placeholder")}
|
||||||
value={cancellationReason}
|
value={cancellationReason}
|
||||||
onChange={(e) => setCancellationReason(e.target.value)}
|
onChange={(e) => setCancellationReason(e.target.value)}
|
||||||
className="dark:bg-darkgray-100 dark:border-darkgray-400 mt-2 mb-4 w-full dark:text-white "
|
className="mt-2 mb-4 w-full "
|
||||||
rows={3}
|
rows={3}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col-reverse rtl:space-x-reverse ">
|
<div className="flex flex-col-reverse rtl:space-x-reverse ">
|
||||||
@@ -77,7 +77,6 @@ export default function CancelBooking(props: Props) {
|
|||||||
{t("nevermind")}
|
{t("nevermind")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="dark:bg-darkmodebrand dark:hover:border-darkmodebrand dark:text-darkmodebrandcontrast bg-brand hover:border-brand text-brandcontrast flex justify-center"
|
|
||||||
data-testid="cancel"
|
data-testid="cancel"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { SkeletonText } from "@calcom/ui";
|
|||||||
|
|
||||||
function SkeletonLoader() {
|
function SkeletonLoader() {
|
||||||
return (
|
return (
|
||||||
<ul className="animate-pulse divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:overflow-hidden">
|
<ul className="divide-subtle border-subtle bg-default animate-pulse divide-y rounded-md border sm:overflow-hidden">
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export const SlotPicker = ({
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-8 px-4 pb-4 sm:mt-0 md:min-w-[300px] md:px-4 lg:min-w-[455px]",
|
"mt-8 px-4 pb-4 sm:mt-0 md:min-w-[300px] md:px-4 lg:min-w-[455px]",
|
||||||
selectedDate ? "sm:dark:border-darkgray-200 border-gray-200 sm:border-r sm:p-4 sm:pr-6" : "sm:p-4"
|
selectedDate ? " border-subtle sm:border-r sm:p-4 sm:pr-6" : "sm:p-4"
|
||||||
)}
|
)}
|
||||||
includedDates={Object.keys(monthSlots).filter((k) => monthSlots[k].length > 0)}
|
includedDates={Object.keys(monthSlots).filter((k) => monthSlots[k].length > 0)}
|
||||||
locale={isLocaleReady ? i18n.language : "en"}
|
locale={isLocaleReady ? i18n.language : "en"}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ const TimeOptions: FC<Props> = ({ onSelectTimeZone }) => {
|
|||||||
<TimezoneSelect
|
<TimezoneSelect
|
||||||
id="timeZone"
|
id="timeZone"
|
||||||
classNames={{
|
classNames={{
|
||||||
singleValue: () => "dark:text-darkgray-600 text-gray-600",
|
singleValue: () => "text-default",
|
||||||
|
dropdownIndicator: () => "text-default",
|
||||||
menu: () => "!w-64 max-w-[90vw]",
|
menu: () => "!w-64 max-w-[90vw]",
|
||||||
}}
|
}}
|
||||||
variant="minimal"
|
variant="minimal"
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import {
|
|||||||
useIsBackgroundTransparent,
|
useIsBackgroundTransparent,
|
||||||
useIsEmbed,
|
useIsEmbed,
|
||||||
} from "@calcom/embed-core/embed-iframe";
|
} from "@calcom/embed-core/embed-iframe";
|
||||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
|
||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
|
import useGetBrandingColours from "@calcom/lib/getBrandColours";
|
||||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||||
@@ -24,7 +24,7 @@ import { getRecurringFreq } from "@calcom/lib/recurringStrings";
|
|||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
|
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
|
||||||
import { trpc } from "@calcom/trpc";
|
import { trpc } from "@calcom/trpc";
|
||||||
import { HeadSeo } from "@calcom/ui";
|
import { HeadSeo, useCalcomTheme } from "@calcom/ui";
|
||||||
import { FiCreditCard, FiUser, FiRefreshCcw } from "@calcom/ui/components/icon";
|
import { FiCreditCard, FiUser, FiRefreshCcw } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import { timeZone as localStorageTimeZone } from "@lib/clock";
|
import { timeZone as localStorageTimeZone } from "@lib/clock";
|
||||||
@@ -58,12 +58,24 @@ const dateQuerySchema = z.object({
|
|||||||
|
|
||||||
export type Props = AvailabilityTeamPageProps | AvailabilityPageProps | DynamicAvailabilityPageProps;
|
export type Props = AvailabilityTeamPageProps | AvailabilityPageProps | DynamicAvailabilityPageProps;
|
||||||
|
|
||||||
|
const useBrandColors = ({ brandColor, darkBrandColor }: { brandColor: string; darkBrandColor: string }) => {
|
||||||
|
const brandTheme = useGetBrandingColours({
|
||||||
|
lightVal: brandColor,
|
||||||
|
darkVal: darkBrandColor,
|
||||||
|
});
|
||||||
|
useCalcomTheme(brandTheme);
|
||||||
|
};
|
||||||
|
|
||||||
const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isEmbed = useIsEmbed(restProps.isEmbed);
|
const isEmbed = useIsEmbed(restProps.isEmbed);
|
||||||
const query = dateQuerySchema.parse(router.query);
|
const query = dateQuerySchema.parse(router.query);
|
||||||
const { rescheduleUid } = query;
|
const { rescheduleUid } = query;
|
||||||
useTheme(profile.theme);
|
useTheme(profile.theme);
|
||||||
|
useBrandColors({
|
||||||
|
brandColor: profile.brandColor,
|
||||||
|
darkBrandColor: profile.darkBrandColor,
|
||||||
|
});
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
||||||
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
|
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
|
||||||
@@ -157,30 +169,27 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
isBrandingHidden={restProps.isBrandingHidden}
|
isBrandingHidden={restProps.isBrandingHidden}
|
||||||
/>
|
/>
|
||||||
<BookingPageTagManager eventType={eventType} />
|
<BookingPageTagManager eventType={eventType} />
|
||||||
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
|
|
||||||
<div>
|
<div>
|
||||||
<main
|
<main
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"flex flex-col md:mx-4",
|
"flex flex-col md:mx-4",
|
||||||
shouldAlignCentrally ? "items-center" : "items-start",
|
shouldAlignCentrally ? "items-center" : "items-start",
|
||||||
!isEmbed && classNames("mx-auto my-0 ease-in-out md:my-24")
|
!isEmbed && classNames("bg-subtle dark:bg-default mx-auto my-0 ease-in-out md:my-24")
|
||||||
)}>
|
)}>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
style={availabilityDatePickerEmbedStyles}
|
style={availabilityDatePickerEmbedStyles}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isBackgroundTransparent
|
isBackgroundTransparent ? "" : "bg-default dark:bg-muted pb-4 md:pb-0",
|
||||||
? ""
|
"border-subtle md:rounded-md md:border",
|
||||||
: "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white pb-4 md:pb-0",
|
|
||||||
"border-bookinglightest md:rounded-md md:border",
|
|
||||||
isEmbed && "mx-auto"
|
isEmbed && "mx-auto"
|
||||||
)}>
|
)}>
|
||||||
<div className="md:flex">
|
<div className="md:flex">
|
||||||
{showEventTypeDetails && (
|
{showEventTypeDetails && (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"sm:dark:border-darkgray-200 flex flex-col border-gray-200 p-5 sm:border-r",
|
" border-subtle flex flex-col p-5 sm:border-r",
|
||||||
"min-w-full md:w-[280px] md:min-w-[280px]",
|
"min-w-full md:w-[230px] md:min-w-[230px]",
|
||||||
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
|
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
|
||||||
)}>
|
)}>
|
||||||
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
|
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
|
||||||
@@ -188,7 +197,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"flex flex-nowrap items-center text-sm font-medium",
|
"flex flex-nowrap items-center text-sm font-medium",
|
||||||
"dark:text-darkgray-600 text-gray-600",
|
" text-default",
|
||||||
"ltr:mr-[10px] rtl:ml-[10px]"
|
"ltr:mr-[10px] rtl:ml-[10px]"
|
||||||
)}>
|
)}>
|
||||||
<FiUser
|
<FiUser
|
||||||
@@ -211,7 +220,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
max={eventType.recurringEvent.count}
|
max={eventType.recurringEvent.count}
|
||||||
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
|
className="w-15 border-default bg-default dark:border-empthasis h-7 rounded-sm text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
||||||
defaultValue={eventType.recurringEvent.count}
|
defaultValue={eventType.recurringEvent.count}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
setRecurringEventCount(parseInt(event?.target.value));
|
setRecurringEventCount(parseInt(event?.target.value));
|
||||||
@@ -243,12 +252,12 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||||||
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
|
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
|
||||||
<div>
|
<div>
|
||||||
<p
|
<p
|
||||||
className="mt-4 mb-3 text-gray-600 dark:text-darkgray-600"
|
className="mt-4 mb-3 text-default"
|
||||||
data-testid="former_time_p_desktop">
|
data-testid="former_time_p_desktop">
|
||||||
{t("former_time")}
|
{t("former_time")}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-500 line-through dark:text-darkgray-600">
|
<p className="text-subtle line-through ">
|
||||||
<CalendarIcon className="ltr:mr-[10px] rtl:ml-[10px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
<CalendarIcon className="ltr:mr-[10px] rtl:ml-[10px] -mt-1 inline-block h-4 w-4 text-subtle" />
|
||||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
|
||||||
import type { EventLocationType } from "@calcom/app-store/locations";
|
import type { EventLocationType } from "@calcom/app-store/locations";
|
||||||
import { getEventLocationType, locationKeyToString } from "@calcom/app-store/locations";
|
|
||||||
import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
|
import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
|
||||||
import { getEventTypeAppData } from "@calcom/app-store/utils";
|
import { getEventTypeAppData } from "@calcom/app-store/utils";
|
||||||
import type { LocationObject } from "@calcom/core/location";
|
import type { LocationObject } from "@calcom/core/location";
|
||||||
@@ -29,10 +28,12 @@ import {
|
|||||||
import getBookingResponsesSchema, {
|
import getBookingResponsesSchema, {
|
||||||
getBookingResponsesPartialSchema,
|
getBookingResponsesPartialSchema,
|
||||||
} from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
} from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
||||||
|
import getLocationOptionsForSelect from "@calcom/features/bookings/lib/getLocationOptionsForSelect";
|
||||||
import { FormBuilderField } from "@calcom/features/form-builder/FormBuilder";
|
import { FormBuilderField } from "@calcom/features/form-builder/FormBuilder";
|
||||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
import { bookingSuccessRedirect } from "@calcom/lib/bookingSuccessRedirect";
|
||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
|
import useGetBrandingColours from "@calcom/lib/getBrandColours";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||||
@@ -40,7 +41,7 @@ import { HttpError } from "@calcom/lib/http-error";
|
|||||||
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { TimeFormat } from "@calcom/lib/timeFormat";
|
import { TimeFormat } from "@calcom/lib/timeFormat";
|
||||||
import { Button, Form, Tooltip } from "@calcom/ui";
|
import { Button, Form, Tooltip, useCalcomTheme } from "@calcom/ui";
|
||||||
import { FiAlertTriangle, FiCalendar, FiRefreshCw, FiUser } from "@calcom/ui/components/icon";
|
import { FiAlertTriangle, FiCalendar, FiRefreshCw, FiUser } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import { timeZone } from "@lib/clock";
|
import { timeZone } from "@lib/clock";
|
||||||
@@ -64,6 +65,14 @@ const BookingDescriptionPayment = dynamic(
|
|||||||
() => import("@components/booking/BookingDescriptionPayment")
|
() => import("@components/booking/BookingDescriptionPayment")
|
||||||
) as unknown as typeof import("@components/booking/BookingDescriptionPayment").default;
|
) as unknown as typeof import("@components/booking/BookingDescriptionPayment").default;
|
||||||
|
|
||||||
|
const useBrandColors = ({ brandColor, darkBrandColor }: { brandColor?: string; darkBrandColor?: string }) => {
|
||||||
|
const brandTheme = useGetBrandingColours({
|
||||||
|
lightVal: brandColor,
|
||||||
|
darkVal: darkBrandColor,
|
||||||
|
});
|
||||||
|
useCalcomTheme(brandTheme);
|
||||||
|
};
|
||||||
|
|
||||||
type BookingPageProps = BookPageProps | TeamBookingPageProps | HashLinkPageProps;
|
type BookingPageProps = BookPageProps | TeamBookingPageProps | HashLinkPageProps;
|
||||||
const BookingFields = ({
|
const BookingFields = ({
|
||||||
fields,
|
fields,
|
||||||
@@ -135,26 +144,14 @@ const BookingFields = ({
|
|||||||
}
|
}
|
||||||
const optionsInputs = field.optionsInputs;
|
const optionsInputs = field.optionsInputs;
|
||||||
|
|
||||||
const options = locations.map((location) => {
|
// TODO: Instead of `getLocationOptionsForSelect` options should be retrieved from dataStore[field.getOptionsAt]. It would make it agnostic of the `name` of the field.
|
||||||
const eventLocation = getEventLocationType(location.type);
|
const options = getLocationOptionsForSelect(locations, t);
|
||||||
const locationString = locationKeyToString(location);
|
options.forEach((option) => {
|
||||||
|
const optionInput = optionsInputs[option.value as keyof typeof optionsInputs];
|
||||||
if (typeof locationString !== "string" || !eventLocation) {
|
|
||||||
// It's possible that location app got uninstalled
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const type = eventLocation.type;
|
|
||||||
const optionInput = optionsInputs[type as keyof typeof optionsInputs];
|
|
||||||
if (optionInput) {
|
if (optionInput) {
|
||||||
optionInput.placeholder = t(eventLocation?.attendeeInputPlaceholder || "");
|
optionInput.placeholder = option.inputPlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
label: t(locationString),
|
|
||||||
value: type,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
field.options = options.filter(
|
field.options = options.filter(
|
||||||
(location): location is NonNullable<(typeof options)[number]> => !!location
|
(location): location is NonNullable<(typeof options)[number]> => !!location
|
||||||
);
|
);
|
||||||
@@ -268,15 +265,19 @@ const BookingPage = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return router.push({
|
const query = {
|
||||||
pathname: `/booking/${uid}`,
|
isSuccessBookingPage: true,
|
||||||
query: {
|
email: bookingForm.getValues("responses.email"),
|
||||||
isSuccessBookingPage: true,
|
eventTypeSlug: eventType.slug,
|
||||||
email: bookingForm.getValues("responses.email"),
|
seatReferenceUid: "seatReferenceUid" in responseData ? responseData.seatReferenceUid : null,
|
||||||
eventTypeSlug: eventType.slug,
|
...(rescheduleUid && booking?.startTime && { formerTime: booking.startTime.toString() }),
|
||||||
seatReferenceUid: "seatReferenceUid" in responseData ? responseData.seatReferenceUid : null,
|
};
|
||||||
...(rescheduleUid && booking?.startTime && { formerTime: booking.startTime.toString() }),
|
|
||||||
},
|
return bookingSuccessRedirect({
|
||||||
|
router,
|
||||||
|
successRedirectUrl: eventType.successRedirectUrl,
|
||||||
|
query,
|
||||||
|
bookingUid: uid,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -284,16 +285,18 @@ const BookingPage = ({
|
|||||||
const recurringMutation = useMutation(createRecurringBooking, {
|
const recurringMutation = useMutation(createRecurringBooking, {
|
||||||
onSuccess: async (responseData = []) => {
|
onSuccess: async (responseData = []) => {
|
||||||
const { uid } = responseData[0] || {};
|
const { uid } = responseData[0] || {};
|
||||||
|
const query = {
|
||||||
return router.push({
|
isSuccessBookingPage: true,
|
||||||
pathname: `/booking/${uid}`,
|
allRemainingBookings: true,
|
||||||
query: {
|
email: bookingForm.getValues("responses.email"),
|
||||||
isSuccessBookingPage: true,
|
eventTypeSlug: eventType.slug,
|
||||||
allRemainingBookings: true,
|
formerTime: booking?.startTime.toString(),
|
||||||
email: bookingForm.getValues("responses.email"),
|
};
|
||||||
eventTypeSlug: eventType.slug,
|
return bookingSuccessRedirect({
|
||||||
formerTime: booking?.startTime.toString(),
|
router,
|
||||||
},
|
successRedirectUrl: eventType.successRedirectUrl,
|
||||||
|
query,
|
||||||
|
bookingUid: uid,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -303,6 +306,10 @@ const BookingPage = ({
|
|||||||
} = useTypedQuery(routerQuerySchema);
|
} = useTypedQuery(routerQuerySchema);
|
||||||
|
|
||||||
useTheme(profile.theme);
|
useTheme(profile.theme);
|
||||||
|
useBrandColors({
|
||||||
|
brandColor: profile.brandColor,
|
||||||
|
darkBrandColor: profile.darkBrandColor,
|
||||||
|
});
|
||||||
|
|
||||||
const querySchema = getBookingResponsesPartialSchema({
|
const querySchema = getBookingResponsesPartialSchema({
|
||||||
eventType: {
|
eventType: {
|
||||||
@@ -512,7 +519,6 @@ const BookingPage = ({
|
|||||||
<link rel="icon" href="/favico.ico" />
|
<link rel="icon" href="/favico.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<BookingPageTagManager eventType={eventType} />
|
<BookingPageTagManager eventType={eventType} />
|
||||||
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
|
|
||||||
<main
|
<main
|
||||||
className={classNames(
|
className={classNames(
|
||||||
shouldAlignCentrally ? "mx-auto" : "",
|
shouldAlignCentrally ? "mx-auto" : "",
|
||||||
@@ -522,16 +528,16 @@ const BookingPage = ({
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"main",
|
"main",
|
||||||
isBackgroundTransparent ? "" : "dark:bg-darkgray-100 bg-white dark:border",
|
isBackgroundTransparent ? "" : "dark:bg-darkgray-100 bg-default dark:border",
|
||||||
"dark:border-darkgray-300 rounded-md sm:border"
|
"dark:border-darkgray-300 rounded-md sm:border"
|
||||||
)}>
|
)}>
|
||||||
<div className="sm:flex">
|
<div className="sm:flex">
|
||||||
{showEventTypeDetails && (
|
{showEventTypeDetails && (
|
||||||
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
|
<div className="sm:dark:border-darkgray-300 text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6">
|
||||||
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
||||||
<BookingDescriptionPayment eventType={eventType} />
|
<BookingDescriptionPayment eventType={eventType} />
|
||||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||||
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
|
<div className="dark:text-inverted text-default items-start text-sm font-medium">
|
||||||
<FiRefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
<FiRefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||||
<p className="-ml-2 inline-block items-center px-2">
|
<p className="-ml-2 inline-block items-center px-2">
|
||||||
{getEveryFreqFor({
|
{getEveryFreqFor({
|
||||||
@@ -560,7 +566,7 @@ const BookingPage = ({
|
|||||||
content={recurringStrings.slice(5).map((timeFormatted, key) => (
|
content={recurringStrings.slice(5).map((timeFormatted, key) => (
|
||||||
<p key={key}>{timeFormatted}</p>
|
<p key={key}>{timeFormatted}</p>
|
||||||
))}>
|
))}>
|
||||||
<p className="dark:text-darkgray-600 text-sm">
|
<p className=" text-sm">
|
||||||
+ {t("plus_more", { count: recurringStrings.length - 5 })}
|
+ {t("plus_more", { count: recurringStrings.length - 5 })}
|
||||||
</p>
|
</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -637,7 +643,6 @@ const BookingPage = ({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="dark:bg-darkmodebrand dark:hover:border-darkmodebrand dark:text-darkmodebrandcontrast bg-brand hover:border-brand text-brandcontrast"
|
|
||||||
data-testid={rescheduleUid ? "confirm-reschedule-button" : "confirm-book-button"}
|
data-testid={rescheduleUid ? "confirm-reschedule-button" : "confirm-book-button"}
|
||||||
loading={mutation.isLoading || recurringMutation.isLoading}>
|
loading={mutation.isLoading || recurringMutation.isLoading}>
|
||||||
{rescheduleUid ? t("reschedule") : t("confirm")}
|
{rescheduleUid ? t("reschedule") : t("confirm")}
|
||||||
@@ -669,7 +674,7 @@ function ErrorMessage({ error }: { error: unknown }) {
|
|||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<FiAlertTriangle className="h-5 w-5 text-blue-400" aria-hidden="true" />
|
<FiAlertTriangle className="h-5 w-5 text-blue-400" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
<div className="ltr:ml-3 rtl:mr-3">
|
<div className="ms-3">
|
||||||
<p className="text-sm text-blue-700">
|
<p className="text-sm text-blue-700">
|
||||||
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}{" "}
|
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}{" "}
|
||||||
{error instanceof HttpError || error instanceof Error ? (
|
{error instanceof HttpError || error instanceof Error ? (
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="locationInput" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="locationInput" className="text-default block text-sm font-medium">
|
||||||
{t(eventLocationType.messageForOrganizer || "")}
|
{t(eventLocationType.messageForOrganizer || "")}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -174,6 +174,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
id="locationInput"
|
id="locationInput"
|
||||||
placeholder={t(eventLocationType.organizerInputPlaceholder || "")}
|
placeholder={t(eventLocationType.organizerInputPlaceholder || "")}
|
||||||
required
|
required
|
||||||
|
className="border-default block w-full rounded-sm text-sm"
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
defaultValue={
|
defaultValue={
|
||||||
defaultLocation ? defaultLocation[eventLocationType.defaultValueVariable] : undefined
|
defaultLocation ? defaultLocation[eventLocationType.defaultValueVariable] : undefined
|
||||||
@@ -182,7 +183,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
errors={locationFormMethods.formState.errors}
|
errors={locationFormMethods.formState.errors}
|
||||||
name={eventLocationType.variable}
|
name={eventLocationType.variable}
|
||||||
className="mt-1 text-sm text-red-500"
|
className="text-error mt-1 text-sm"
|
||||||
as="p"
|
as="p"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,7 +209,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return <p className="text-sm">{getMessageForOrganizer(selectedLocation, t)}</p>;
|
return <p className="text-default text-sm">{getMessageForOrganizer(selectedLocation, t)}</p>;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -216,16 +217,16 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
<Dialog open={isOpenDialog} onOpenChange={(open) => setShowLocationModal(open)}>
|
<Dialog open={isOpenDialog} onOpenChange={(open) => setShowLocationModal(open)}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div className="flex flex-row space-x-3">
|
<div className="flex flex-row space-x-3">
|
||||||
<div className="bg-secondary-100 mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
|
<div className="bg-subtle mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
|
||||||
<FiMapPin className="text-primary-600 h-6 w-6" />
|
<FiMapPin className="text-emphasis h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
<h3 className="text-emphasis text-lg font-medium leading-6" id="modal-title">
|
||||||
{t("edit_location")}
|
{t("edit_location")}
|
||||||
</h3>
|
</h3>
|
||||||
{!booking && (
|
{!booking && (
|
||||||
<p className="text-sm text-gray-400">
|
<p className="text-default text-sm">
|
||||||
<Trans i18nKey="cant_find_the_right_video_app_visit_our_app_store">
|
<Trans i18nKey="cant_find_the_right_video_app_visit_our_app_store">
|
||||||
Can't find the right video app? Visit our
|
Can't find the right video app? Visit our
|
||||||
<Link className="cursor-pointer text-blue-500 underline" href="/apps/categories/video">
|
<Link className="cursor-pointer text-blue-500 underline" href="/apps/categories/video">
|
||||||
@@ -240,8 +241,8 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
|||||||
|
|
||||||
{booking && (
|
{booking && (
|
||||||
<>
|
<>
|
||||||
<p className="mt-6 mb-2 ml-1 text-sm font-bold text-black">{t("current_location")}:</p>
|
<p className="text-emphasis mt-6 mb-2 ml-1 text-sm font-bold">{t("current_location")}:</p>
|
||||||
<p className="mb-2 ml-1 text-sm text-black">
|
<p className="text-emphasis mb-2 ml-1 text-sm">
|
||||||
{getHumanReadableLocationValue(booking.location, t)}
|
{getHumanReadableLocationValue(booking.location, t)}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ export const RescheduleDialog = (props: IRescheduleDialog) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pt-1">
|
<div className="pt-1">
|
||||||
<DialogHeader title={t("send_reschedule_request")} />
|
<DialogHeader title={t("send_reschedule_request")} />
|
||||||
<p className="text-sm text-gray-500">{t("reschedule_modal_description")}</p>
|
<p className="text-subtle text-sm">{t("reschedule_modal_description")}</p>
|
||||||
<p className="mt-6 mb-2 text-sm font-bold text-black">
|
<p className="text-emphasis mt-6 mb-2 text-sm font-bold">
|
||||||
{t("reason_for_reschedule_request")}
|
{t("reason_for_reschedule_request")}
|
||||||
<span className="font-normal text-gray-500"> (Optional)</span>
|
<span className="text-subtle font-normal"> (Optional)</span>
|
||||||
</p>
|
</p>
|
||||||
<TextArea
|
<TextArea
|
||||||
data-testid="reschedule_reason"
|
data-testid="reschedule_reason"
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ const ErrorDebugPanel: React.FC<{ error: Props["error"]; children?: never }> = (
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden bg-white shadow sm:rounded-lg">
|
<div className="bg-default overflow-hidden shadow sm:rounded-lg">
|
||||||
<div className="border-t border-gray-200 px-4 py-5 sm:p-0">
|
<div className="border-subtle border-t px-4 py-5 sm:p-0">
|
||||||
<dl className="sm:divide-y sm:divide-gray-200">
|
<dl className="sm:divide-subtle sm:divide-y">
|
||||||
{debugMap.map(([key, value]) => {
|
{debugMap.map(([key, value]) => {
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
return (
|
return (
|
||||||
<div key={key} className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
|
<div key={key} className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
|
||||||
<dt className="text-sm font-bold text-black">{key}</dt>
|
<dt className="text-emphasis text-sm font-bold">{key}</dt>
|
||||||
<dd className="mt-1 text-sm text-black sm:col-span-2 sm:mt-0">{value}</dd>
|
<dd className="text-emphasis mt-1 text-sm sm:col-span-2 sm:mt-0">{value}</dd>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -53,11 +53,11 @@ export const ErrorPage: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="min-h-screen bg-white px-4">
|
<div className="bg-default min-h-screen px-4">
|
||||||
<main className="mx-auto max-w-xl pb-6 pt-16 sm:pt-24">
|
<main className="mx-auto max-w-xl pb-6 pt-16 sm:pt-24">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">{statusCode}</p>
|
<p className="text-emphasis text-sm font-semibold uppercase tracking-wide">{statusCode}</p>
|
||||||
<h1 className="mt-2 text-4xl font-extrabold tracking-tight text-gray-900 sm:text-5xl">
|
<h1 className="text-emphasis mt-2 text-4xl font-extrabold tracking-tight sm:text-5xl">
|
||||||
{message}
|
{message}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ const EventTypeScheduleDetails = () => {
|
|||||||
schedule?.schedule.filter((item) => item.days.includes((dayNum + 1) % 7)) || [];
|
schedule?.schedule.filter((item) => item.days.includes((dayNum + 1) % 7)) || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 rounded border px-6 pb-4">
|
<div className="border-default space-y-4 rounded border px-6 pb-4">
|
||||||
<ol className="table border-collapse text-sm">
|
<ol className="table border-collapse text-sm">
|
||||||
{weekdayNames(i18n.language, 1, "long").map((day, index) => {
|
{weekdayNames(i18n.language, 1, "long").map((day, index) => {
|
||||||
const isAvailable = !!filterDays(index).length;
|
const isAvailable = !!filterDays(index).length;
|
||||||
@@ -128,8 +128,8 @@ const EventTypeScheduleDetails = () => {
|
|||||||
<li key={day} className="my-6 flex border-transparent last:mb-2">
|
<li key={day} className="my-6 flex border-transparent last:mb-2">
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"w-20 font-medium sm:w-32",
|
"w-20 font-medium sm:w-32 ",
|
||||||
!isAvailable && "text-gray-500 opacity-50"
|
!isAvailable ? "text-subtle line-through" : "text-default"
|
||||||
)}>
|
)}>
|
||||||
{day}
|
{day}
|
||||||
</span>
|
</span>
|
||||||
@@ -138,25 +138,25 @@ const EventTypeScheduleDetails = () => {
|
|||||||
) : isAvailable ? (
|
) : isAvailable ? (
|
||||||
<div className="space-y-3 text-right">
|
<div className="space-y-3 text-right">
|
||||||
{filterDays(index).map((dayRange, i) => (
|
{filterDays(index).map((dayRange, i) => (
|
||||||
<div key={i} className="flex items-center leading-4">
|
<div key={i} className="text-default flex items-center leading-4">
|
||||||
<span className="w-16 sm:w-28 sm:text-left">
|
<span className="w-16 sm:w-28 sm:text-left">
|
||||||
{format(dayRange.startTime, timeFormat === 12)}
|
{format(dayRange.startTime, timeFormat === 12)}
|
||||||
</span>
|
</span>
|
||||||
<span className="ltr:ml-4 rtl:mr-4">-</span>
|
<span className="ms-4">-</span>
|
||||||
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
|
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span className="ml-6 text-gray-500 opacity-50 sm:ml-0">{t("unavailable")}</span>
|
<span className="text-subtle ml-6 sm:ml-0">{t("unavailable")}</span>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ol>
|
</ol>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:justify-between">
|
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:justify-between">
|
||||||
<span className="flex items-center justify-center text-sm text-gray-600 sm:justify-start">
|
<span className="text-default flex items-center justify-center text-sm sm:justify-start">
|
||||||
<FiGlobe className="ltr:mr-2 rtl:ml-2" />
|
<FiGlobe className="ltr:mr-2 rtl:ml-2" />
|
||||||
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
|
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
|
||||||
</span>
|
</span>
|
||||||
@@ -194,7 +194,7 @@ const EventTypeSchedule = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="availability" className="mb-2 block text-sm font-medium leading-none text-gray-700">
|
<label htmlFor="availability" className="text-default mb-2 block text-sm font-medium leading-none">
|
||||||
{t("availability")}
|
{t("availability")}
|
||||||
</label>
|
</label>
|
||||||
<Controller
|
<Controller
|
||||||
|
|||||||
@@ -58,35 +58,35 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
|
|||||||
className="mb-0"
|
className="mb-0"
|
||||||
/>
|
/>
|
||||||
<div className="pt-6 text-sm">
|
<div className="pt-6 text-sm">
|
||||||
<div className="mb-6 rounded-md bg-gray-100 p-2">
|
<div className="bg-subtle mb-6 rounded-md p-2">
|
||||||
<h1 className="mb-2 ml-1 font-medium text-gray-900">{t("available_variables")}</h1>
|
<h1 className="text-emphasis mb-2 ml-1 font-medium">{t("available_variables")}</h1>
|
||||||
<div className="mb-2.5 flex font-normal">
|
<div className="mb-2.5 flex font-normal">
|
||||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Event type title}`}</p>
|
<p className="text-subtle ml-1 mr-5 w-28">{`{Event type title}`}</p>
|
||||||
<p className="text-gray-900">{t("event_name_info")}</p>
|
<p className="text-emphasis">{t("event_name_info")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2.5 flex font-normal">
|
<div className="mb-2.5 flex font-normal">
|
||||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Organiser}`}</p>
|
<p className="text-subtle ml-1 mr-5 w-28">{`{Organiser}`}</p>
|
||||||
<p className="text-gray-900">{t("your_full_name")}</p>
|
<p className="text-emphasis">{t("your_full_name")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2.5 flex font-normal">
|
<div className="mb-2.5 flex font-normal">
|
||||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Scheduler}`}</p>
|
<p className="text-subtle ml-1 mr-5 w-28">{`{Scheduler}`}</p>
|
||||||
<p className="text-gray-900">{t("scheduler_full_name")}</p>
|
<p className="text-emphasis">{t("scheduler_full_name")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-1 flex font-normal">
|
<div className="mb-1 flex font-normal">
|
||||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Location}`}</p>
|
<p className="text-subtle ml-1 mr-5 w-28">{`{Location}`}</p>
|
||||||
<p className="text-gray-900">{t("location_info")}</p>
|
<p className="text-emphasis">{t("location_info")}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="mb-2 text-[14px] font-medium leading-4">{t("preview")}</h1>
|
<h1 className="mb-2 text-[14px] font-medium leading-4">{t("preview")}</h1>
|
||||||
<div
|
<div
|
||||||
className="flex h-[212px] w-full rounded-md border-y bg-cover bg-center"
|
className="flex h-[212px] w-full rounded-md border-y bg-cover bg-center dark:invert"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: "url(/calendar-preview.svg)",
|
backgroundImage: "url(/calendar-preview.svg)",
|
||||||
}}>
|
}}>
|
||||||
<div className="m-auto flex items-center justify-center self-stretch">
|
<div className="m-auto flex items-center justify-center self-stretch">
|
||||||
<div className="mt-3 ml-11 box-border h-[110px] w-[120px] flex-col items-start gap-1 rounded-md border border-solid border-black bg-gray-100 text-[12px] leading-3">
|
<div className="bg-subtle mt-3 ml-11 box-border h-[110px] w-[120px] flex-col items-start gap-1 rounded-md border border-solid border-black text-[12px] leading-3">
|
||||||
<p className="overflow-hidden text-ellipsis p-1.5 font-medium text-gray-900">{previewText}</p>
|
<p className="text-emphasis overflow-hidden text-ellipsis p-1.5 font-medium">{previewText}</p>
|
||||||
<p className="ml-1.5 text-[10px] font-normal text-gray-600">8 - 10 AM</p>
|
<p className="text-default ml-1.5 text-[10px] font-normal">8 - 10 AM</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,13 +8,15 @@ import { v5 as uuidv5 } from "uuid";
|
|||||||
|
|
||||||
import type { EventNameObjectType } from "@calcom/core/event";
|
import type { EventNameObjectType } from "@calcom/core/event";
|
||||||
import { getEventName } from "@calcom/core/event";
|
import { getEventName } from "@calcom/core/event";
|
||||||
|
import getLocationsOptionsForSelect from "@calcom/features/bookings/lib/getLocationOptionsForSelect";
|
||||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||||
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
||||||
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
|
import { classNames } from "@calcom/lib";
|
||||||
|
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import type { Prisma } from "@calcom/prisma/client";
|
import type { Prisma } from "@calcom/prisma/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Badge, Button, Checkbox, Label, SettingsToggle, showToast, TextField, Tooltip } from "@calcom/ui";
|
import { Button, Checkbox, Label, SettingsToggle, showToast, TextField, Tooltip } from "@calcom/ui";
|
||||||
import { FiEdit, FiCopy } from "@calcom/ui/components/icon";
|
import { FiEdit, FiCopy } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
import RequiresConfirmationController from "./RequiresConfirmationController";
|
import RequiresConfirmationController from "./RequiresConfirmationController";
|
||||||
@@ -99,7 +101,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
<Link
|
<Link
|
||||||
href="/apps/categories/calendar"
|
href="/apps/categories/calendar"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="text-sm text-gray-600 hover:text-gray-900">
|
className="hover:text-emphasis text-default text-sm">
|
||||||
{t("add_another_calendar")}
|
{t("add_another_calendar")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +120,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600">{t("select_which_cal")}</p>
|
<p className="text-default text-sm">{t("select_which_cal")}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@@ -134,28 +136,33 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
StartIcon={FiEdit}
|
StartIcon={FiEdit}
|
||||||
variant="icon"
|
variant="icon"
|
||||||
color="minimal"
|
color="minimal"
|
||||||
className="hover:stroke-3 min-w-fit px-0 hover:bg-transparent hover:text-black"
|
className="hover:stroke-3 hover:text-emphasis min-w-fit px-0 hover:bg-transparent"
|
||||||
onClick={() => setShowEventNameTip((old) => !old)}
|
onClick={() => setShowEventNameTip((old) => !old)}
|
||||||
aria-label="edit custom name"
|
aria-label="edit custom name"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<FormBuilder
|
<FormBuilder
|
||||||
title={t("booking_questions_title")}
|
title={t("booking_questions_title")}
|
||||||
description={t("booking_questions_description")}
|
description={t("booking_questions_description")}
|
||||||
addFieldLabel={t("add_a_booking_question")}
|
addFieldLabel={t("add_a_booking_question")}
|
||||||
formProp="bookingFields"
|
formProp="bookingFields"
|
||||||
|
dataStore={{
|
||||||
|
options: {
|
||||||
|
locations: getLocationsOptionsForSelect(eventType?.locations ?? [], t),
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<RequiresConfirmationController
|
<RequiresConfirmationController
|
||||||
seatsEnabled={seatsEnabled}
|
seatsEnabled={seatsEnabled}
|
||||||
metadata={eventType.metadata}
|
metadata={eventType.metadata}
|
||||||
requiresConfirmation={requiresConfirmation}
|
requiresConfirmation={requiresConfirmation}
|
||||||
onRequiresConfirmation={setRequiresConfirmation}
|
onRequiresConfirmation={setRequiresConfirmation}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="hideCalendarNotes"
|
name="hideCalendarNotes"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -169,7 +176,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="successRedirectUrl"
|
name="successRedirectUrl"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -183,9 +190,10 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
setRedirectUrlVisible(e);
|
setRedirectUrlVisible(e);
|
||||||
onChange(e ? value : "");
|
onChange(e ? value : "");
|
||||||
}}>
|
}}>
|
||||||
{/* Textfield has some margin by default we remove that so we can keep consitant aligment */}
|
{/* Textfield has some margin by default we remove that so we can keep consistent alignment */}
|
||||||
<div className="lg:-ml-2">
|
<div className="lg:-ml-2 lg:-mb-2">
|
||||||
<TextField
|
<TextField
|
||||||
|
className="w-full"
|
||||||
label={t("redirect_success_booking")}
|
label={t("redirect_success_booking")}
|
||||||
labelSrOnly
|
labelSrOnly
|
||||||
placeholder={t("external_redirect_url")}
|
placeholder={t("external_redirect_url")}
|
||||||
@@ -194,28 +202,19 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
defaultValue={eventType.successRedirectUrl || ""}
|
defaultValue={eventType.successRedirectUrl || ""}
|
||||||
{...formMethods.register("successRedirectUrl")}
|
{...formMethods.register("successRedirectUrl")}
|
||||||
/>
|
/>
|
||||||
<div className="mt-2 flex">
|
<div
|
||||||
<Checkbox
|
className={classNames(
|
||||||
description={t("disable_success_page")}
|
"p-1 text-sm text-orange-600",
|
||||||
// Disable if it's not Self Hosted or if the redirect url is not set
|
formMethods.getValues("successRedirectUrl") ? "block" : "hidden"
|
||||||
disabled={!IS_SELF_HOSTED || !formMethods.watch("successRedirectUrl")}
|
)}>
|
||||||
{...formMethods.register("metadata.disableSuccessPage")}
|
{t("redirect_url_warning")}
|
||||||
/>
|
|
||||||
{/*TODO: Extract it out into a component when used more than once*/}
|
|
||||||
{!IS_SELF_HOSTED && (
|
|
||||||
<Link href="https://cal.com/pricing" target="_blank">
|
|
||||||
<Badge variant="orange" className="ml-2">
|
|
||||||
Platform Only
|
|
||||||
</Badge>
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SettingsToggle>
|
</SettingsToggle>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<SettingsToggle
|
<SettingsToggle
|
||||||
data-testid="hashedLinkCheck"
|
data-testid="hashedLinkCheck"
|
||||||
title={t("private_link")}
|
title={t("private_link")}
|
||||||
@@ -248,7 +247,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
showToast(t("enabled_after_update_description"), "warning");
|
showToast(t("enabled_after_update_description"), "warning");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="hover:stroke-3 hover:bg-transparent hover:text-black"
|
className="hover:stroke-3 hover:text-emphasis hover:bg-transparent"
|
||||||
type="button">
|
type="button">
|
||||||
<FiCopy />
|
<FiCopy />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -257,7 +256,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</SettingsToggle>
|
</SettingsToggle>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="seatsPerTimeSlotEnabled"
|
name="seatsPerTimeSlotEnabled"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{!isLoading && notInstalledApps?.length ? (
|
{!isLoading && notInstalledApps?.length ? (
|
||||||
<h2 className="mt-0 mb-2 text-lg font-semibold text-gray-900">Available Apps</h2>
|
<h2 className="text-emphasis mt-0 mb-2 text-lg font-semibold">Available Apps</h2>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="before:border-0">
|
<div className="before:border-0">
|
||||||
{notInstalledApps?.map((app) => (
|
{notInstalledApps?.map((app) => (
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="bookingLimits"
|
name="bookingLimits"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -276,7 +276,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
</SettingsToggle>
|
</SettingsToggle>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="durationLimits"
|
name="durationLimits"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -303,7 +303,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
</SettingsToggle>
|
</SettingsToggle>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr className="border-subtle" />
|
||||||
<Controller
|
<Controller
|
||||||
name="periodType"
|
name="periodType"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -322,14 +322,14 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mb-2 flex flex-wrap items-center text-sm",
|
"text-default mb-2 flex flex-wrap items-center text-sm",
|
||||||
watchPeriodType === "UNLIMITED" && "pointer-events-none opacity-30"
|
watchPeriodType === "UNLIMITED" && "pointer-events-none opacity-30"
|
||||||
)}
|
)}
|
||||||
key={period.type}>
|
key={period.type}>
|
||||||
<RadioGroup.Item
|
<RadioGroup.Item
|
||||||
id={period.type}
|
id={period.type}
|
||||||
value={period.type}
|
value={period.type}
|
||||||
className="min-w-4 flex h-4 w-4 cursor-pointer items-center rounded-full border border-black bg-white focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
|
className="min-w-4 bg-default flex h-4 w-4 cursor-pointer items-center rounded-full border border-black focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
|
||||||
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
|
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
|
||||||
</RadioGroup.Item>
|
</RadioGroup.Item>
|
||||||
{period.prefix ? <span>{period.prefix} </span> : null}
|
{period.prefix ? <span>{period.prefix} </span> : null}
|
||||||
@@ -337,14 +337,14 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
<div className="flex h-9">
|
<div className="flex h-9">
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
className="block w-16 rounded-md border-gray-300 py-3 text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
className="border-default block w-16 rounded-md py-3 text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
||||||
placeholder="30"
|
placeholder="30"
|
||||||
{...formMethods.register("periodDays", { valueAsNumber: true })}
|
{...formMethods.register("periodDays", { valueAsNumber: true })}
|
||||||
defaultValue={eventType.periodDays || 30}
|
defaultValue={eventType.periodDays || 30}
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
id=""
|
id=""
|
||||||
className="block h-9 w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-sm focus:outline-none"
|
className="border-default bg-default text-default block h-9 w-full rounded-md py-2 pl-3 pr-10 text-sm focus:outline-none"
|
||||||
{...formMethods.register("periodCountCalendarDays")}
|
{...formMethods.register("periodCountCalendarDays")}
|
||||||
defaultValue={eventType.periodCountCalendarDays ? "1" : "0"}>
|
defaultValue={eventType.periodCountCalendarDays ? "1" : "0"}>
|
||||||
<option value="1">{t("calendar_days")}</option>
|
<option value="1">{t("calendar_days")}</option>
|
||||||
@@ -353,7 +353,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{period.type === "RANGE" && (
|
{period.type === "RANGE" && (
|
||||||
<div className="inline-flex space-x-2 ltr:ml-2 ltr:mr-2 rtl:ml-2 rtl:space-x-reverse">
|
<div className="ms-2 me-2 inline-flex space-x-2 rtl:space-x-reverse">
|
||||||
<Controller
|
<Controller
|
||||||
name="periodDates"
|
name="periodDates"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
@@ -373,9 +373,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{period.suffix ? (
|
{period.suffix ? <span className="ms-2 me-2"> {period.suffix}</span> : null}
|
||||||
<span className="ltr:ml-2 ltr:mr-2 rtl:ml-2"> {period.suffix}</span>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -229,16 +229,8 @@ export const EventSetupTab = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
onClick={() => {
|
|
||||||
locationFormMethods.setValue("locationType", location.type);
|
|
||||||
locationFormMethods.unregister("locationLink");
|
|
||||||
locationFormMethods.unregister("locationAddress");
|
|
||||||
locationFormMethods.unregister("locationPhoneNumber");
|
|
||||||
setEditingLocationType(location.type);
|
|
||||||
openLocationModal(location.type);
|
|
||||||
}}
|
|
||||||
key={`${location.type}${index}`}
|
key={`${location.type}${index}`}
|
||||||
className="mb-2 rounded-md border border-gray-300 py-1.5 px-2 hover:cursor-pointer">
|
className="border-default text-default mb-2 rounded-md border py-1.5 px-2 hover:cursor-pointer">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<img
|
<img
|
||||||
@@ -246,7 +238,7 @@ export const EventSetupTab = (
|
|||||||
className="h-4 w-4"
|
className="h-4 w-4"
|
||||||
alt={`${eventLocationType.label} logo`}
|
alt={`${eventLocationType.label} logo`}
|
||||||
/>
|
/>
|
||||||
<span className="line-clamp-1 text-sm ltr:ml-1 rtl:mr-1">{eventLabel}</span>
|
<span className="line-clamp-1 ms-1 text-sm">{eventLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<button
|
<button
|
||||||
@@ -260,11 +252,11 @@ export const EventSetupTab = (
|
|||||||
openLocationModal(location.type);
|
openLocationModal(location.type);
|
||||||
}}
|
}}
|
||||||
aria-label={t("edit")}
|
aria-label={t("edit")}
|
||||||
className="mr-1 p-1 text-gray-500 hover:text-gray-900">
|
className="hover:text-emphasis text-subtle mr-1 p-1">
|
||||||
<FiEdit2 className="h-4 w-4" />
|
<FiEdit2 className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onClick={() => removeLocation(location)} aria-label={t("remove")}>
|
<button type="button" onClick={() => removeLocation(location)} aria-label={t("remove")}>
|
||||||
<FiX className="border-l-1 h-6 w-6 pl-1 text-gray-500 hover:text-gray-900 " />
|
<FiX className="border-l-1 hover:text-emphasis text-subtle h-6 w-6 pl-1 " />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -275,7 +267,7 @@ export const EventSetupTab = (
|
|||||||
(location) =>
|
(location) =>
|
||||||
location.type === MeetLocationType && destinationCalendar?.integration !== "google_calendar"
|
location.type === MeetLocationType && destinationCalendar?.integration !== "google_calendar"
|
||||||
) && (
|
) && (
|
||||||
<div className="flex text-sm text-gray-600">
|
<div className="text-default flex text-sm">
|
||||||
<FiCheck className="mt-0.5 mr-1.5 h-2 w-2.5" />
|
<FiCheck className="mt-0.5 mr-1.5 h-2 w-2.5" />
|
||||||
<Trans i18nKey="event_type_requres_google_cal">
|
<Trans i18nKey="event_type_requres_google_cal">
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const CheckedHostField = ({
|
|||||||
options?: Options<CheckedSelectOption>;
|
options?: Options<CheckedSelectOption>;
|
||||||
} & Omit<Partial<ComponentProps<typeof CheckedTeamSelect>>, "onChange" | "value">) => {
|
} & Omit<Partial<ComponentProps<typeof CheckedTeamSelect>>, "onChange" | "value">) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col space-y-5 bg-gray-50 p-4">
|
<div className="bg-muted flex flex-col space-y-5 p-4">
|
||||||
<div>
|
<div>
|
||||||
<Label>{labelText}</Label>
|
<Label>{labelText}</Label>
|
||||||
<CheckedTeamSelect
|
<CheckedTeamSelect
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ function EventTypeSingleLayout({
|
|||||||
heading={eventType.title}
|
heading={eventType.title}
|
||||||
CTA={
|
CTA={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<div className="hidden items-center rounded-md px-2 sm:hover:bg-gray-100 lg:flex">
|
<div className="sm:hover:bg-subtle hidden items-center rounded-md px-2 lg:flex">
|
||||||
<Skeleton
|
<Skeleton
|
||||||
as={Label}
|
as={Label}
|
||||||
htmlFor="hiddenSwitch"
|
htmlFor="hiddenSwitch"
|
||||||
@@ -215,7 +215,7 @@ function EventTypeSingleLayout({
|
|||||||
<VerticalDivider className="hidden lg:block" />
|
<VerticalDivider className="hidden lg:block" />
|
||||||
|
|
||||||
{/* TODO: Figure out why combined isnt working - works in storybook */}
|
{/* TODO: Figure out why combined isnt working - works in storybook */}
|
||||||
<ButtonGroup combined containerProps={{ className: "border-gray-300 hidden lg:flex" }}>
|
<ButtonGroup combined containerProps={{ className: "border-default hidden lg:flex" }}>
|
||||||
{/* We have to warp this in tooltip as it has a href which disabels the tooltip on buttons */}
|
{/* We have to warp this in tooltip as it has a href which disabels the tooltip on buttons */}
|
||||||
<Tooltip content={t("preview")}>
|
<Tooltip content={t("preview")}>
|
||||||
<Button
|
<Button
|
||||||
@@ -263,7 +263,7 @@ function EventTypeSingleLayout({
|
|||||||
<Button className="lg:hidden" StartIcon={FiMoreHorizontal} variant="icon" color="secondary" />
|
<Button className="lg:hidden" StartIcon={FiMoreHorizontal} variant="icon" color="secondary" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent style={{ minWidth: "200px" }}>
|
<DropdownMenuContent style={{ minWidth: "200px" }}>
|
||||||
<DropdownMenuItem className="focus:ring-gray-100">
|
<DropdownMenuItem className="focus:ring-muted">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
target="_blank"
|
target="_blank"
|
||||||
type="button"
|
type="button"
|
||||||
@@ -273,7 +273,7 @@ function EventTypeSingleLayout({
|
|||||||
{t("preview")}
|
{t("preview")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem className="focus:ring-gray-100">
|
<DropdownMenuItem className="focus:ring-muted">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
type="button"
|
type="button"
|
||||||
StartIcon={FiLink}
|
StartIcon={FiLink}
|
||||||
@@ -284,7 +284,7 @@ function EventTypeSingleLayout({
|
|||||||
{t("copy_link")}
|
{t("copy_link")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem className="focus:ring-gray-100">
|
<DropdownMenuItem className="focus:ring-muted">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
type="button"
|
type="button"
|
||||||
color="destructive"
|
color="destructive"
|
||||||
@@ -295,7 +295,7 @@ function EventTypeSingleLayout({
|
|||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<div className="flex h-9 flex-row items-center justify-between py-2 px-4 sm:hover:bg-gray-100">
|
<div className="sm:hover:bg-subtle flex h-9 flex-row items-center justify-between py-2 px-4">
|
||||||
<Skeleton
|
<Skeleton
|
||||||
as={Label}
|
as={Label}
|
||||||
htmlFor="hiddenSwitch"
|
htmlFor="hiddenSwitch"
|
||||||
@@ -312,7 +312,7 @@ function EventTypeSingleLayout({
|
|||||||
</div>
|
</div>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<div className="border-l-2 border-gray-300" />
|
<div className="border-default border-l-2" />
|
||||||
<Button
|
<Button
|
||||||
className="ml-4 lg:ml-0"
|
className="ml-4 lg:ml-0"
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -339,7 +339,7 @@ function EventTypeSingleLayout({
|
|||||||
<div className="w-full ltr:mr-2 rtl:ml-2">
|
<div className="w-full ltr:mr-2 rtl:ml-2">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-4 rounded-md border-gray-200 bg-white sm:mx-0 xl:mt-0",
|
"bg-default border-subtle mt-4 rounded-md sm:mx-0 xl:mt-0",
|
||||||
disableBorder ? "border-0 " : "p-2 md:border md:p-6"
|
disableBorder ? "border-0 " : "p-2 md:border md:p-6"
|
||||||
)}>
|
)}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ export default function RecurringEventController({
|
|||||||
{recurringEventState && (
|
{recurringEventState && (
|
||||||
<div data-testid="recurring-event-collapsible" className="text-sm">
|
<div data-testid="recurring-event-collapsible" className="text-sm">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">{t("repeats_every")}</p>
|
<p className="text-emphasis ltr:mr-2 rtl:ml-2">{t("repeats_every")}</p>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
max="20"
|
max="20"
|
||||||
className="block h-[36px] w-16 rounded-md border-gray-300 text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
className="border-default bg-default text-default block h-[36px] w-16 rounded-md text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
||||||
defaultValue={recurringEventState.interval}
|
defaultValue={recurringEventState.interval}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
const newVal = {
|
const newVal = {
|
||||||
@@ -89,12 +89,12 @@ export default function RecurringEventController({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex items-center">
|
<div className="mt-4 flex items-center">
|
||||||
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">{t("for_a_maximum_of")}</p>
|
<p className="text-emphasis ltr:mr-2 rtl:ml-2">{t("for_a_maximum_of")}</p>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
max="20"
|
max="20"
|
||||||
className="block h-[36px] w-16 rounded-md border-gray-300 text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
className="border-default bg-default text-default block h-[36px] w-16 rounded-md text-sm [appearance:textfield] ltr:mr-2 rtl:ml-2"
|
||||||
defaultValue={recurringEventState.count}
|
defaultValue={recurringEventState.count}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
const newVal = {
|
const newVal = {
|
||||||
@@ -105,7 +105,7 @@ export default function RecurringEventController({
|
|||||||
setRecurringEventState(newVal);
|
setRecurringEventState(newVal);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">
|
<p className="text-emphasis ltr:mr-2 rtl:ml-2">
|
||||||
{t("events", {
|
{t("events", {
|
||||||
count: recurringEventState.count,
|
count: recurringEventState.count,
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type z from "zod";
|
|||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||||
import { Input, Label, SettingsToggle } from "@calcom/ui";
|
import { Input, Label, SettingsToggle, RadioField } from "@calcom/ui";
|
||||||
|
|
||||||
type RequiresConfirmationControllerProps = {
|
type RequiresConfirmationControllerProps = {
|
||||||
metadata: z.infer<typeof EventTypeMetaDataSchema>;
|
metadata: z.infer<typeof EventTypeMetaDataSchema>;
|
||||||
@@ -77,72 +77,69 @@ export default function RequiresConfirmationController({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div className="-ml-2 flex flex-col flex-wrap justify-start gap-y-2 space-y-2">
|
<div className="flex flex-col flex-wrap justify-start gap-y-2 space-y-2">
|
||||||
<div className="flex items-center">
|
<RadioField label={t("always_requires_confirmation")} id="always" value="always" />
|
||||||
<RadioGroup.Item
|
<RadioField
|
||||||
id="always"
|
label={
|
||||||
value="always"
|
<>
|
||||||
className="min-w-4 flex h-4 w-4 cursor-pointer items-center rounded-full border border-black bg-white focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
|
<Trans
|
||||||
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
|
i18nKey="when_booked_with_less_than_notice"
|
||||||
</RadioGroup.Item>
|
defaults="When booked with less than <time></time> notice"
|
||||||
<Label htmlFor="always" className="!m-0 flex items-center">
|
components={{
|
||||||
{t("always_requires_confirmation")}
|
time: (
|
||||||
</Label>
|
<div className="mx-2 flex">
|
||||||
</div>
|
<Input
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
onChange={(evt) => {
|
||||||
|
const val = Number(evt.target?.value);
|
||||||
|
setRequiresConfirmationSetup({
|
||||||
|
unit:
|
||||||
|
requiresConfirmationSetup?.unit ??
|
||||||
|
defaultRequiresConfirmationSetup.unit,
|
||||||
|
time: val,
|
||||||
|
});
|
||||||
|
formMethods.setValue("metadata.requiresConfirmationThreshold.time", val);
|
||||||
|
}}
|
||||||
|
className="border-default !m-0 block w-16 rounded-md text-sm [appearance:textfield]"
|
||||||
|
defaultValue={metadata?.requiresConfirmationThreshold?.time || 30}
|
||||||
|
/>
|
||||||
|
<select
|
||||||
|
onChange={(evt) => {
|
||||||
|
const val = evt.target.value as UnitTypeLongPlural;
|
||||||
|
setRequiresConfirmationSetup({
|
||||||
|
time:
|
||||||
|
requiresConfirmationSetup?.time ??
|
||||||
|
defaultRequiresConfirmationSetup.time,
|
||||||
|
unit: val,
|
||||||
|
});
|
||||||
|
formMethods.setValue("metadata.requiresConfirmationThreshold.unit", val);
|
||||||
|
}}
|
||||||
|
className="border-default text-default bg-default ml-2 block h-9 rounded-md py-2 pl-3 pr-10 text-sm focus:outline-none"
|
||||||
|
defaultValue={
|
||||||
|
metadata?.requiresConfirmationThreshold?.unit ||
|
||||||
|
defaultRequiresConfirmationSetup.unit
|
||||||
|
}>
|
||||||
|
<option value="minutes">{t("minute_timeUnit")}</option>
|
||||||
|
<option value="hours">{t("hour_timeUnit")}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
id="notice"
|
||||||
|
value="notice"
|
||||||
|
/>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<RadioGroup.Item
|
<RadioGroup.Item
|
||||||
id="notice"
|
id="notice"
|
||||||
value="notice"
|
value="notice"
|
||||||
className="min-w-4 flex h-4 w-4 cursor-pointer items-center rounded-full border border-black bg-white focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
|
className="min-w-4 bg-default flex h-4 w-4 cursor-pointer items-center rounded-full border border-black focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
|
||||||
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
|
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
|
||||||
</RadioGroup.Item>
|
</RadioGroup.Item>
|
||||||
<Label htmlFor="notice" className="!m-0 flex items-center">
|
<Label htmlFor="notice" className="!m-0 flex items-center" />
|
||||||
<Trans
|
|
||||||
i18nKey="when_booked_with_less_than_notice"
|
|
||||||
defaults="When booked with less than <time></time> notice"
|
|
||||||
components={{
|
|
||||||
time: (
|
|
||||||
<div className="mx-2 flex">
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
min={1}
|
|
||||||
onChange={(evt) => {
|
|
||||||
const val = Number(evt.target?.value);
|
|
||||||
setRequiresConfirmationSetup({
|
|
||||||
unit:
|
|
||||||
requiresConfirmationSetup?.unit ??
|
|
||||||
defaultRequiresConfirmationSetup.unit,
|
|
||||||
time: val,
|
|
||||||
});
|
|
||||||
formMethods.setValue("metadata.requiresConfirmationThreshold.time", val);
|
|
||||||
}}
|
|
||||||
className="!m-0 block w-16 rounded-md border-gray-300 text-sm [appearance:textfield]"
|
|
||||||
defaultValue={metadata?.requiresConfirmationThreshold?.time || 30}
|
|
||||||
/>
|
|
||||||
<select
|
|
||||||
onChange={(evt) => {
|
|
||||||
const val = evt.target.value as UnitTypeLongPlural;
|
|
||||||
setRequiresConfirmationSetup({
|
|
||||||
time:
|
|
||||||
requiresConfirmationSetup?.time ??
|
|
||||||
defaultRequiresConfirmationSetup.time,
|
|
||||||
unit: val,
|
|
||||||
});
|
|
||||||
formMethods.setValue("metadata.requiresConfirmationThreshold.unit", val);
|
|
||||||
}}
|
|
||||||
className="ml-2 block h-9 rounded-md border-gray-300 py-2 pl-3 pr-10 text-sm focus:outline-none"
|
|
||||||
defaultValue={
|
|
||||||
metadata?.requiresConfirmationThreshold?.unit ||
|
|
||||||
defaultRequiresConfirmationSetup.unit
|
|
||||||
}>
|
|
||||||
<option value="minutes">{t("minute_timeUnit")}</option>
|
|
||||||
<option value="hours">{t("hour_timeUnit")}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup.Root>
|
</RadioGroup.Root>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ function SkeletonLoader() {
|
|||||||
<SkeletonText className="h-4 w-24" />
|
<SkeletonText className="h-4 w-24" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
|
<ul className="border-subtle bg-default divide-subtle divide-y rounded-md border sm:mx-0 sm:overflow-hidden">
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
<SkeletonItem />
|
<SkeletonItem />
|
||||||
@@ -32,11 +32,11 @@ function SkeletonItem() {
|
|||||||
<div className="">
|
<div className="">
|
||||||
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
|
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
|
||||||
<li className="flex items-center whitespace-nowrap">
|
<li className="flex items-center whitespace-nowrap">
|
||||||
<FiClock className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
|
<FiClock className="text-subtle mt-0.5 mr-1.5 inline h-4 w-4" />
|
||||||
<SkeletonText className="h-4 w-12" />
|
<SkeletonText className="h-4 w-12" />
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-center whitespace-nowrap">
|
<li className="flex items-center whitespace-nowrap">
|
||||||
<FiUser className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
|
<FiUser className="text-subtle mt-0.5 mr-1.5 inline h-4 w-4" />
|
||||||
<SkeletonText className="h-4 w-12" />
|
<SkeletonText className="h-4 w-12" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import { Button } from "@calcom/ui";
|
|||||||
interface ICalendarItem {
|
interface ICalendarItem {
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
imageSrc: string;
|
logo: string;
|
||||||
type: App["type"];
|
type: App["type"];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CalendarItem = (props: ICalendarItem) => {
|
const CalendarItem = (props: ICalendarItem) => {
|
||||||
const { title, imageSrc, type } = props;
|
const { title, logo, type } = props;
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row items-center justify-between p-5">
|
<div className="flex flex-row items-center justify-between p-5">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<img src={imageSrc} alt={title} className="h-8 w-8" />
|
<img src={logo} alt={title} className="h-8 w-8" />
|
||||||
<p className="text-sm font-bold">{title}</p>
|
<p className="text-sm font-bold">{title}</p>
|
||||||
</div>
|
</div>
|
||||||
<InstallAppButtonWithoutPlanCheck
|
<InstallAppButtonWithoutPlanCheck
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ const ConnectedCalendarItem = (prop: IConnectedCalendarItem) => {
|
|||||||
<p className="font-sans text-sm font-bold leading-5">
|
<p className="font-sans text-sm font-bold leading-5">
|
||||||
{name}
|
{name}
|
||||||
{/* Temporarily removed till we use it on another place */}
|
{/* Temporarily removed till we use it on another place */}
|
||||||
{/* <span className="mx-1 rounded-[4px] bg-green-100 py-[2px] px-[6px] font-sans text-xs font-medium text-green-600">
|
{/* <span className="mx-1 rounded-[4px] bg-success py-[2px] px-[6px] font-sans text-xs font-medium text-green-600">
|
||||||
{t("default")}
|
{t("default")}
|
||||||
</span> */}
|
</span> */}
|
||||||
</p>
|
</p>
|
||||||
<div className="fle-row flex">
|
<div className="fle-row flex">
|
||||||
<span
|
<span
|
||||||
title={externalId}
|
title={externalId}
|
||||||
className="max-w-44 mt-1 overflow-hidden text-ellipsis whitespace-nowrap font-sans text-sm text-gray-500">
|
className="max-w-44 text-subtle mt-1 overflow-hidden text-ellipsis whitespace-nowrap font-sans text-sm">
|
||||||
{externalId}{" "}
|
{externalId}{" "}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,11 +44,11 @@ const ConnectedCalendarItem = (prop: IConnectedCalendarItem) => {
|
|||||||
{/* <Button
|
{/* <Button
|
||||||
color="minimal"
|
color="minimal"
|
||||||
type="button"
|
type="button"
|
||||||
className="ml-auto flex rounded-md border border-gray-200 py-[10x] px-4 font-sans text-sm">
|
className="ml-auto flex rounded-md border border-subtle py-[10x] px-4 font-sans text-sm">
|
||||||
{t("edit")}
|
{t("edit")}
|
||||||
</Button> */}
|
</Button> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-[1px] w-full border-b border-gray-200" />
|
<div className="border-subtle h-[1px] w-full border-b" />
|
||||||
<div>
|
<div>
|
||||||
<ul className="p-4">
|
<ul className="p-4">
|
||||||
{calendars?.map((calendar, i) => (
|
{calendars?.map((calendar, i) => (
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const CreateEventsOnCalendarSelect = (props: ICreateEventsOnCalendarSelectProps)
|
|||||||
<>
|
<>
|
||||||
<div className="mt-6 flex flex-row">
|
<div className="mt-6 flex flex-row">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<label htmlFor="createEventsOn" className="flex text-sm font-medium text-gray-700">
|
<label htmlFor="createEventsOn" className="text-default flex text-sm font-medium">
|
||||||
{t("create_events_on")}
|
{t("create_events_on")}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
firstCalendar &&
|
firstCalendar &&
|
||||||
firstCalendar.integration &&
|
firstCalendar.integration &&
|
||||||
firstCalendar.integration.title &&
|
firstCalendar.integration.title &&
|
||||||
firstCalendar.integration.imageSrc && (
|
firstCalendar.integration.logo && (
|
||||||
<>
|
<>
|
||||||
<List className="rounded-md border border-gray-200 bg-white p-0 dark:bg-black">
|
<List className="bg-default border-subtle rounded-md border p-0 dark:bg-black">
|
||||||
<ConnectedCalendarItem
|
<ConnectedCalendarItem
|
||||||
key={firstCalendar.integration.title}
|
key={firstCalendar.integration.title}
|
||||||
name={firstCalendar.integration.title}
|
name={firstCalendar.integration.title}
|
||||||
logo={firstCalendar.integration.imageSrc}
|
logo={firstCalendar.integration.logo}
|
||||||
externalId={
|
externalId={
|
||||||
firstCalendar && firstCalendar.calendars && firstCalendar.calendars.length > 0
|
firstCalendar && firstCalendar.calendars && firstCalendar.calendars.length > 0
|
||||||
? firstCalendar.calendars[0].externalId
|
? firstCalendar.calendars[0].externalId
|
||||||
@@ -49,22 +49,22 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
</List>
|
</List>
|
||||||
{/* Create event on selected calendar */}
|
{/* Create event on selected calendar */}
|
||||||
<CreateEventsOnCalendarSelect calendar={destinationCalendar} />
|
<CreateEventsOnCalendarSelect calendar={destinationCalendar} />
|
||||||
<p className="mt-4 text-sm text-gray-500">{t("connect_calendars_from_app_store")}</p>
|
<p className="text-subtle mt-4 text-sm">{t("connect_calendars_from_app_store")}</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Connect calendars list */}
|
{/* Connect calendars list */}
|
||||||
{firstCalendar === undefined && queryIntegrations.data && queryIntegrations.data.items.length > 0 && (
|
{firstCalendar === undefined && queryIntegrations.data && queryIntegrations.data.items.length > 0 && (
|
||||||
<List className="mx-1 divide-y divide-gray-200 rounded-md border border-gray-200 bg-white p-0 dark:bg-black sm:mx-0">
|
<List className="bg-default divide-subtle border-subtle mx-1 divide-y rounded-md border p-0 dark:bg-black sm:mx-0">
|
||||||
{queryIntegrations.data &&
|
{queryIntegrations.data &&
|
||||||
queryIntegrations.data.items.map((item) => (
|
queryIntegrations.data.items.map((item) => (
|
||||||
<li key={item.title}>
|
<li key={item.title}>
|
||||||
{item.title && item.imageSrc && (
|
{item.title && item.logo && (
|
||||||
<CalendarItem
|
<CalendarItem
|
||||||
type={item.type}
|
type={item.type}
|
||||||
title={item.title}
|
title={item.title}
|
||||||
description={item.description}
|
description={item.description}
|
||||||
imageSrc={item.imageSrc}
|
logo={item.logo}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
@@ -73,7 +73,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{queryIntegrations.isLoading && (
|
{queryIntegrations.isLoading && (
|
||||||
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white p-0 dark:bg-black">
|
<ul className="bg-default divide-subtle border-subtle divide-y rounded-md border p-0 dark:bg-black">
|
||||||
{[0, 0, 0, 0].map((_item, index) => {
|
{[0, 0, 0, 0].map((_item, index) => {
|
||||||
return (
|
return (
|
||||||
<li className="flex w-full flex-row justify-center border-b-0 py-6" key={index}>
|
<li className="flex w-full flex-row justify-center border-b-0 py-6" key={index}>
|
||||||
@@ -89,7 +89,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
type="button"
|
type="button"
|
||||||
data-testid="save-calendar-button"
|
data-testid="save-calendar-button"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm text-white",
|
"text-inverted mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm",
|
||||||
disabledNextButton ? "cursor-not-allowed opacity-20" : ""
|
disabledNextButton ? "cursor-not-allowed opacity-20" : ""
|
||||||
)}
|
)}
|
||||||
onClick={() => nextStep()}
|
onClick={() => nextStep()}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const SetupAvailability = (props: ISetupAvailabilityProps) => {
|
|||||||
const updateSchedule = trpc.viewer.availability.schedule.update.useMutation(mutationOptions);
|
const updateSchedule = trpc.viewer.availability.schedule.update.useMutation(mutationOptions);
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
className="w-full bg-white text-black dark:bg-opacity-5 dark:text-white"
|
className="bg-default dark:text-inverted text-emphasis w-full dark:bg-opacity-5"
|
||||||
form={availabilityForm}
|
form={availabilityForm}
|
||||||
handleSubmit={async (values) => {
|
handleSubmit={async (values) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ const UserProfile = (props: IUserProfileProps) => {
|
|||||||
name="avatar"
|
name="avatar"
|
||||||
id="avatar"
|
id="avatar"
|
||||||
placeholder="URL"
|
placeholder="URL"
|
||||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 text-sm focus:border-gray-800 focus:outline-none focus:ring-gray-800"
|
className="border-default focus:ring-empthasis mt-1 block w-full rounded-sm border px-3 py-2 text-sm focus:border-gray-800 focus:outline-none"
|
||||||
defaultValue={imageSrc}
|
defaultValue={imageSrc}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center px-4">
|
<div className="flex items-center px-4">
|
||||||
@@ -142,19 +142,19 @@ const UserProfile = (props: IUserProfileProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<fieldset className="mt-8">
|
<fieldset className="mt-8">
|
||||||
<Label className="mb-2 block text-sm font-medium text-gray-700">{t("about")}</Label>
|
<Label className="text-default mb-2 block text-sm font-medium">{t("about")}</Label>
|
||||||
<Editor
|
<Editor
|
||||||
getText={() => md.render(getValues("bio") || user?.bio || "")}
|
getText={() => md.render(getValues("bio") || user?.bio || "")}
|
||||||
setText={(value: string) => setValue("bio", turndown(value))}
|
setText={(value: string) => setValue("bio", turndown(value))}
|
||||||
excludedToolbarItems={["blockType"]}
|
excludedToolbarItems={["blockType"]}
|
||||||
/>
|
/>
|
||||||
<p className="mt-2 font-sans text-sm font-normal text-gray-600 dark:text-white">
|
<p className="dark:text-inverted text-default mt-2 font-sans text-sm font-normal">
|
||||||
{t("few_sentences_about_yourself")}
|
{t("few_sentences_about_yourself")}
|
||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm text-white">
|
className="text-inverted mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm">
|
||||||
{t("finish")}
|
{t("finish")}
|
||||||
<ArrowRightIcon className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
|
<ArrowRightIcon className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
|||||||
|
|
||||||
{/* Full name textfield */}
|
{/* Full name textfield */}
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<label htmlFor="name" className="mb-2 block text-sm font-medium text-gray-700">
|
<label htmlFor="name" className="text-default mb-2 block text-sm font-medium">
|
||||||
{t("full_name")}
|
{t("full_name")}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -85,7 +85,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
|||||||
type="text"
|
type="text"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
className="w-full rounded-md border border-gray-300 text-sm"
|
className="border-default w-full rounded-md border text-sm"
|
||||||
/>
|
/>
|
||||||
{errors.name && (
|
{errors.name && (
|
||||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||||
@@ -95,7 +95,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{/* Timezone select field */}
|
{/* Timezone select field */}
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="timeZone" className="text-default block text-sm font-medium">
|
||||||
{t("timezone")}
|
{t("timezone")}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
|||||||
className="mt-2 w-full rounded-md text-sm"
|
className="mt-2 w-full rounded-md text-sm"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p className="mt-3 flex flex-row font-sans text-xs leading-tight text-gray-500 dark:text-white">
|
<p className="text-subtle dark:text-inverted mt-3 flex flex-row font-sans text-xs leading-tight">
|
||||||
{t("current_time")} {dayjs().tz(selectedTimeZone).format("LT").toString().toLowerCase()}
|
{t("current_time")} {dayjs().tz(selectedTimeZone).format("LT").toString().toLowerCase()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export default function WizardLayout({
|
|||||||
}, [router.asPath]);
|
}, [router.asPath]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dark:bg-brand dark:text-brand-contrast min-h-screen text-black" data-testid="onboarding">
|
<div
|
||||||
|
className="dark:bg-brand dark:text-brand-contrast text-emphasis min-h-screen"
|
||||||
|
data-testid="onboarding">
|
||||||
<div>
|
<div>
|
||||||
<Toaster position="bottom-right" />
|
<Toaster position="bottom-right" />
|
||||||
</div>
|
</div>
|
||||||
@@ -34,7 +36,7 @@ export default function WizardLayout({
|
|||||||
<div className="mx-auto sm:max-w-[520px]">
|
<div className="mx-auto sm:max-w-[520px]">
|
||||||
<header>
|
<header>
|
||||||
<p className="font-cal mb-3 text-[28px] font-medium leading-7">{title} </p>
|
<p className="font-cal mb-3 text-[28px] font-medium leading-7">{title} </p>
|
||||||
<p className="font-sans text-sm font-normal text-gray-500">{subtitle} </p>
|
<p className="text-subtle font-sans text-sm font-normal">{subtitle} </p>
|
||||||
</header>
|
</header>
|
||||||
<Steps maxSteps={maxSteps} currentStep={currentStep} navigateToStep={noop} />
|
<Steps maxSteps={maxSteps} currentStep={currentStep} navigateToStep={noop} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,14 +59,14 @@ const ChangePasswordSection = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}>
|
<form className="divide-subtle divide-y lg:col-span-9" onSubmit={changePasswordHandler}>
|
||||||
<div className="py-6 lg:pb-5">
|
<div className="py-6 lg:pb-5">
|
||||||
<div className="my-3">
|
<div className="my-3">
|
||||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("change_password")}</h2>
|
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">{t("change_password")}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col space-y-2 sm:flex-row sm:space-y-0">
|
<div className="flex flex-col space-y-2 sm:flex-row sm:space-y-0">
|
||||||
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-1/2">
|
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-1/2">
|
||||||
<label htmlFor="current_password" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="current_password" className="text-default block text-sm font-medium">
|
||||||
{t("current_password")}
|
{t("current_password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -77,13 +77,13 @@ const ChangePasswordSection = () => {
|
|||||||
name="current_password"
|
name="current_password"
|
||||||
id="current_password"
|
id="current_password"
|
||||||
required
|
required
|
||||||
className="block w-full rounded-sm border-gray-300 text-sm"
|
className="border-default block w-full rounded-sm text-sm"
|
||||||
placeholder={t("your_old_password")}
|
placeholder={t("your_old_password")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full sm:w-1/2">
|
<div className="w-full sm:w-1/2">
|
||||||
<label htmlFor="new_password" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="new_password" className="text-default block text-sm font-medium">
|
||||||
{t("new_password")}
|
{t("new_password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -94,7 +94,7 @@ const ChangePasswordSection = () => {
|
|||||||
value={newPassword}
|
value={newPassword}
|
||||||
required
|
required
|
||||||
onInput={(e) => setNewPassword(e.currentTarget.value)}
|
onInput={(e) => setNewPassword(e.currentTarget.value)}
|
||||||
className="block w-full rounded-sm border-gray-300 text-sm"
|
className="border-default block w-full rounded-sm text-sm"
|
||||||
placeholder={t("super_secure_new_password")}
|
placeholder={t("super_secure_new_password")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -70,10 +70,10 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
labelProps={{
|
labelProps={{
|
||||||
className: "block text-sm font-medium text-gray-700",
|
className: "block text-sm font-medium text-default",
|
||||||
}}
|
}}
|
||||||
{...form.register("password")}
|
{...form.register("password")}
|
||||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-black focus:outline-none focus:ring-black"
|
className="border-default mt-1 block w-full rounded-md border px-3 py-2 text-sm focus:border-black focus:outline-none focus:ring-black"
|
||||||
/>
|
/>
|
||||||
<Label className="mt-4"> {t("2fa_code")}</Label>
|
<Label className="mt-4"> {t("2fa_code")}</Label>
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
|
<Button type="submit" className="ms-2 me-2" disabled={isDisabling}>
|
||||||
{t("disable")}
|
{t("disable")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="secondary" onClick={onCancel}>
|
<Button color="secondary" onClick={onCancel}>
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ const DisableUserImpersonation = ({ disableImpersonation }: { disableImpersonati
|
|||||||
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
|
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">
|
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">
|
||||||
{t("user_impersonation_heading")}
|
{t("user_impersonation_heading")}
|
||||||
</h2>
|
</h2>
|
||||||
<Badge className="ml-2 text-xs" variant={!disableImpersonation ? "success" : "gray"}>
|
<Badge className="ml-2 text-xs" variant={!disableImpersonation ? "success" : "gray"}>
|
||||||
{!disableImpersonation ? t("enabled") : t("disabled")}
|
{!disableImpersonation ? t("enabled") : t("disabled")}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-sm text-gray-500">{t("user_impersonation_description")}</p>
|
<p className="text-subtle mt-1 text-sm">{t("user_impersonation_description")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 sm:mt-0 sm:self-center">
|
<div className="mt-5 sm:mt-0 sm:self-center">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||||||
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
||||||
<form onSubmit={handleSetup}>
|
<form onSubmit={handleSetup}>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label htmlFor="password" className="mt-4 block text-sm font-medium text-gray-700">
|
<label htmlFor="password" className="text-default mt-4 block text-sm font-medium">
|
||||||
{t("password")}
|
{t("password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
@@ -146,7 +146,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||||||
required
|
required
|
||||||
value={password}
|
value={password}
|
||||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||||
className="block w-full rounded-sm border-gray-300 text-sm"
|
className="border-default block w-full rounded-sm text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -178,22 +178,19 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||||||
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
className="ms-2 me-2"
|
||||||
onClick={handleSetup}
|
onClick={handleSetup}
|
||||||
disabled={password.length === 0 || isSubmitting}>
|
disabled={password.length === 0 || isSubmitting}>
|
||||||
{t("continue")}
|
{t("continue")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
||||||
<Button
|
<Button type="submit" className="ms-2 me-2" onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
||||||
type="submit"
|
|
||||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
|
||||||
onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
|
||||||
{t("continue")}
|
{t("continue")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
||||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
|
<Button type="submit" className="ms-2 me-2" disabled={isSubmitting}>
|
||||||
{t("enable")}
|
{t("enable")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
|
|||||||
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
|
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("2fa")}</h2>
|
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">{t("2fa")}</h2>
|
||||||
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
|
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
|
||||||
{enabled ? t("enabled") : t("disabled")}
|
{enabled ? t("enabled") : t("disabled")}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-sm text-gray-500">{t("add_an_extra_layer_of_security")}</p>
|
<p className="text-subtle mt-1 text-sm">{t("add_an_extra_layer_of_security")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 sm:mt-0 sm:self-center">
|
<div className="mt-5 sm:mt-0 sm:self-center">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ const TwoFactorModalHeader = ({ title, description }: { title: string; descripti
|
|||||||
return (
|
return (
|
||||||
<div className="mb-4 sm:flex sm:items-start">
|
<div className="mb-4 sm:flex sm:items-start">
|
||||||
<div className="bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
<div className="bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||||
<FiShield className="h-6 w-6 text-white" />
|
<FiShield className="text-inverted h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||||
<h3 className="font-cal text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
<h3 className="font-cal text-emphasis text-lg font-medium leading-6" id="modal-title">
|
||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-gray-400">{description}</p>
|
<p className="text-muted text-sm">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export function CalendarSwitch(props: {
|
|||||||
{props.defaultSelected && (
|
{props.defaultSelected && (
|
||||||
<Badge variant="gray">
|
<Badge variant="gray">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<FiArrowLeft className="mr-1" /> {t("adding_events_to")}
|
<FiArrowLeft className="text-default mr-1" /> {t("adding_events_to")}
|
||||||
</div>
|
</div>
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ const DisableTwoFactorAuthModal = ({
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
labelProps={{
|
labelProps={{
|
||||||
className: "block text-sm font-medium text-gray-700",
|
className: "block text-sm font-medium text-default",
|
||||||
}}
|
}}
|
||||||
{...form.register("password")}
|
{...form.register("password")}
|
||||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-black focus:outline-none focus:ring-black"
|
className="border-default mt-1 block w-full rounded-md border px-3 py-2 text-sm focus:border-black focus:outline-none focus:ring-black"
|
||||||
/>
|
/>
|
||||||
<Label className="mt-4"> {t("2fa_code")}</Label>
|
<Label className="mt-4"> {t("2fa_code")}</Label>
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ const DisableTwoFactorAuthModal = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
|
<Button type="submit" className="ms-2 me-2" disabled={isDisabling}>
|
||||||
{t("disable")}
|
{t("disable")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="secondary" onClick={onCancel}>
|
<Button color="secondary" onClick={onCancel}>
|
||||||
|
|||||||
@@ -171,22 +171,19 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
|
|||||||
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
className="ms-2 me-2"
|
||||||
onClick={handleSetup}
|
onClick={handleSetup}
|
||||||
disabled={password.length === 0 || isSubmitting}>
|
disabled={password.length === 0 || isSubmitting}>
|
||||||
{t("continue")}
|
{t("continue")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
||||||
<Button
|
<Button type="submit" className="ms-2 me-2" onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
||||||
type="submit"
|
|
||||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
|
||||||
onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
|
||||||
{t("continue")}
|
{t("continue")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
||||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
|
<Button type="submit" className="ms-2 me-2" disabled={isSubmitting}>
|
||||||
{t("enable")}
|
{t("enable")}
|
||||||
</Button>
|
</Button>
|
||||||
</WithStep>
|
</WithStep>
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export const AdminUser = (props: { onSubmit: () => void; onError: () => void; on
|
|||||||
<Label htmlFor="username" className={classNames(longWebsiteUrl && "mb-0")}>
|
<Label htmlFor="username" className={classNames(longWebsiteUrl && "mb-0")}>
|
||||||
<span className="block">{t("username")}</span>
|
<span className="block">{t("username")}</span>
|
||||||
{longWebsiteUrl && (
|
{longWebsiteUrl && (
|
||||||
<small className="items-centerpx-3 mt-2 inline-flex rounded-t-md border border-b-0 border-gray-300 bg-gray-100 py-1 px-3 text-gray-500">
|
<small className="items-centerpx-3 bg-subtle border-default text-subtle mt-2 inline-flex rounded-t-md border border-b-0 py-1 px-3">
|
||||||
{process.env.NEXT_PUBLIC_WEBSITE_URL}
|
{process.env.NEXT_PUBLIC_WEBSITE_URL}
|
||||||
</small>
|
</small>
|
||||||
)}
|
)}
|
||||||
@@ -119,7 +119,7 @@ export const AdminUser = (props: { onSubmit: () => void; onError: () => void; on
|
|||||||
<TextField
|
<TextField
|
||||||
addOnLeading={
|
addOnLeading={
|
||||||
!longWebsiteUrl && (
|
!longWebsiteUrl && (
|
||||||
<span className="inline-flex items-center rounded-none px-3 text-sm text-gray-500">
|
<span className="text-subtle inline-flex items-center rounded-none px-3 text-sm">
|
||||||
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
|
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ const ChooseLicense = (
|
|||||||
<RadioGroup.Item value="FREE">
|
<RadioGroup.Item value="FREE">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"cursor-pointer space-y-2 rounded-md border bg-white p-4 hover:border-black",
|
"bg-default cursor-pointer space-y-2 rounded-md border p-4 hover:border-black",
|
||||||
value === "FREE" && "ring-2 ring-black"
|
value === "FREE" && "ring-2 ring-black"
|
||||||
)}>
|
)}>
|
||||||
<h2 className="font-cal text-xl text-black">{t("agplv3_license")}</h2>
|
<h2 className="font-cal text-emphasis text-xl">{t("agplv3_license")}</h2>
|
||||||
<p className="font-medium text-green-800">{t("free_license_fee")}</p>
|
<p className="font-medium text-green-800">{t("free_license_fee")}</p>
|
||||||
<p className="text-gray-500">{t("forever_open_and_free")}</p>
|
<p className="text-subtle">{t("forever_open_and_free")}</p>
|
||||||
<ul className="ml-4 list-disc text-left text-xs text-gray-500">
|
<ul className="text-subtle ml-4 list-disc text-left text-xs">
|
||||||
<li>{t("required_to_keep_your_code_open_source")}</li>
|
<li>{t("required_to_keep_your_code_open_source")}</li>
|
||||||
<li>{t("cannot_repackage_and_resell")}</li>
|
<li>{t("cannot_repackage_and_resell")}</li>
|
||||||
<li>{t("no_enterprise_features")}</li>
|
<li>{t("no_enterprise_features")}</li>
|
||||||
@@ -53,15 +53,15 @@ const ChooseLicense = (
|
|||||||
<RadioGroup.Item value="EE">
|
<RadioGroup.Item value="EE">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"cursor-pointer space-y-2 rounded-md border bg-white p-4 hover:border-black",
|
"bg-default cursor-pointer space-y-2 rounded-md border p-4 hover:border-black",
|
||||||
value === "EE" && "ring-2 ring-black"
|
value === "EE" && "ring-2 ring-black"
|
||||||
)}>
|
)}>
|
||||||
<h2 className="font-cal text-xl text-black">{t("ee_enterprise_license")}</h2>
|
<h2 className="font-cal text-emphasis text-xl">{t("ee_enterprise_license")}</h2>
|
||||||
<p className="font-medium text-green-800">
|
<p className="font-medium text-green-800">
|
||||||
{t("enterprise_booking_fee", { enterprise_booking_fee: ENTERPRISE_BOOKING_FEE })}
|
{t("enterprise_booking_fee", { enterprise_booking_fee: ENTERPRISE_BOOKING_FEE })}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-500">{t("enterprise_license_includes")}</p>
|
<p className="text-subtle">{t("enterprise_license_includes")}</p>
|
||||||
<ul className="ml-4 list-disc text-left text-xs text-gray-500">
|
<ul className="text-subtle ml-4 list-disc text-left text-xs">
|
||||||
<li>{t("no_need_to_keep_your_code_open_source")}</li>
|
<li>{t("no_need_to_keep_your_code_open_source")}</li>
|
||||||
<li>{t("repackage_rebrand_resell")}</li>
|
<li>{t("repackage_rebrand_resell")}</li>
|
||||||
<li>{t("a_vast_suite_of_enterprise_features")}</li>
|
<li>{t("a_vast_suite_of_enterprise_features")}</li>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const EnterpriseLicense = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...formMethods}>
|
<FormProvider {...formMethods}>
|
||||||
<form {...rest} className="space-y-4 rounded-md bg-white px-8 py-10" onSubmit={handleSubmit}>
|
<form {...rest} className="bg-default space-y-4 rounded-md px-8 py-10" onSubmit={handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
className="w-full justify-center text-lg"
|
className="w-full justify-center text-lg"
|
||||||
@@ -97,8 +97,8 @@ const EnterpriseLicense = (
|
|||||||
{t("purchase_license")}
|
{t("purchase_license")}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="relative flex justify-center">
|
<div className="relative flex justify-center">
|
||||||
<hr className="my-8 w-full border-[1.5px] border-gray-200" />
|
<hr className="border-subtle my-8 w-full border-[1.5px]" />
|
||||||
<span className="absolute mt-[22px] bg-white px-3.5 text-sm">OR</span>
|
<span className="bg-default absolute mt-[22px] px-3.5 text-sm">OR</span>
|
||||||
</div>
|
</div>
|
||||||
{t("already_have_key")}
|
{t("already_have_key")}
|
||||||
<Controller
|
<Controller
|
||||||
@@ -108,7 +108,7 @@ const EnterpriseLicense = (
|
|||||||
<TextField
|
<TextField
|
||||||
{...formMethods.register("licenseKey")}
|
{...formMethods.register("licenseKey")}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mb-0 group-hover:border-gray-400",
|
"group-hover:border-emphasis mb-0",
|
||||||
(checkLicenseLoading || (errors.licenseKey === undefined && isDirty)) && "border-r-0"
|
(checkLicenseLoading || (errors.licenseKey === undefined && isDirty)) && "border-r-0"
|
||||||
)}
|
)}
|
||||||
placeholder="xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"
|
placeholder="xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"
|
||||||
@@ -116,8 +116,8 @@ const EnterpriseLicense = (
|
|||||||
value={value}
|
value={value}
|
||||||
addOnFilled={false}
|
addOnFilled={false}
|
||||||
addOnClassname={classNames(
|
addOnClassname={classNames(
|
||||||
"hover:border-gray-300",
|
"hover:border-default",
|
||||||
errors.licenseKey === undefined && isDirty && "group-hover:border-gray-400"
|
errors.licenseKey === undefined && isDirty && "group-hover:border-emphasis"
|
||||||
)}
|
)}
|
||||||
addOnSuffix={
|
addOnSuffix={
|
||||||
checkLicenseLoading ? (
|
checkLicenseLoading ? (
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ const StepDone = (props: {
|
|||||||
router.replace(props.nextStepPath);
|
router.replace(props.nextStepPath);
|
||||||
}}>
|
}}>
|
||||||
<div className="min-h-36 my-6 flex flex-col items-center justify-center">
|
<div className="min-h-36 my-6 flex flex-col items-center justify-center">
|
||||||
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
|
<div className="dark:bg-default flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600">
|
||||||
<FiCheck className="inline-block h-10 w-10 text-white dark:bg-white dark:text-gray-600" />
|
<FiCheck className="text-inverted dark:bg-default dark:text-default inline-block h-10 w-10" />
|
||||||
</div>
|
</div>
|
||||||
<div className="max-w-[420px] text-center">
|
<div className="max-w-[420px] text-center">
|
||||||
<h2 className="mt-6 mb-1 text-lg font-medium dark:text-gray-300">{t("all_done")}</h2>
|
<h2 className="mt-6 mb-1 text-lg font-medium dark:text-gray-300">{t("all_done")}</h2>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import Link from "next/link";
|
|||||||
|
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
import { md } from "@calcom/lib/markdownIt";
|
||||||
import type { TeamWithMembers } from "@calcom/lib/server/queries/teams";
|
import type { TeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||||
import { Avatar } from "@calcom/ui";
|
import { Avatar } from "@calcom/ui";
|
||||||
|
|
||||||
@@ -18,20 +19,20 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Link key={member.id} href={`/${member.username}`}>
|
<Link key={member.id} href={`/${member.username}`}>
|
||||||
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
|
<div className="sm:min-w-80 sm:max-w-80 bg-default hover:bg-muted border-subtle group flex min-h-full flex-col space-y-2 rounded-md border p-4 hover:cursor-pointer">
|
||||||
<Avatar
|
<Avatar
|
||||||
size="md"
|
size="md"
|
||||||
alt={member.name || ""}
|
alt={member.name || ""}
|
||||||
imageSrc={WEBAPP_URL + "/" + member.username + "/avatar.png"}
|
imageSrc={WEBAPP_URL + "/" + member.username + "/avatar.png"}
|
||||||
/>
|
/>
|
||||||
<section className="line-clamp-4 mt-2 w-full space-y-1">
|
<section className="line-clamp-4 mt-2 w-full space-y-1">
|
||||||
<p className="font-medium text-gray-900 dark:text-white">{member.name}</p>
|
<p className="text-default font-medium">{member.name}</p>
|
||||||
<div className="line-clamp-3 overflow-ellipsis text-sm font-normal text-gray-500 dark:text-white">
|
<div className="line-clamp-3 text-subtle overflow-ellipsis text-sm font-normal">
|
||||||
{!isBioEmpty ? (
|
{!isBioEmpty ? (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="dark:text-darkgray-600 text-sm text-gray-500 [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
className=" text-subtle text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
||||||
dangerouslySetInnerHTML={{ __html: member.safeBio || "" }}
|
dangerouslySetInnerHTML={{ __html: md.render(member.bio || "") }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -24,18 +24,18 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
|
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
|
||||||
{props.heading && <h2 className="font-cal text-center text-3xl text-gray-900">{props.heading}</h2>}
|
{props.heading && <h2 className="font-cal text-emphasis text-center text-3xl">{props.heading}</h2>}
|
||||||
</div>
|
</div>
|
||||||
{props.loading && (
|
{props.loading && (
|
||||||
<div className="absolute z-50 flex h-screen w-full items-center bg-gray-50">
|
<div className="bg-muted absolute z-50 flex h-screen w-full items-center">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="mb-auto mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
<div className="mb-auto mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||||
<div className="mx-2 rounded-md border border-gray-200 bg-white px-4 py-10 sm:px-10">
|
<div className="bg-default border-subtle mx-2 rounded-md border px-4 py-10 sm:px-10">
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-8 text-center text-sm text-gray-600">{props.footerText}</div>
|
<div className="text-default mt-8 text-center text-sm">{props.footerText}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const EditableHeading = function EditableHeading({
|
|||||||
<label className="min-w-8 relative inline-block">
|
<label className="min-w-8 relative inline-block">
|
||||||
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value} </span>
|
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value} </span>
|
||||||
{!isEditing && isReady && (
|
{!isEditing && isReady && (
|
||||||
<FiEdit2 className=" ml-1 -mt-px inline h-3 w-3 text-gray-500 group-hover:text-gray-500" />
|
<FiEdit2 className=" text-subtle group-hover:text-subtle ml-1 -mt-px inline h-3 w-3" />
|
||||||
)}
|
)}
|
||||||
<input
|
<input
|
||||||
{...passThroughProps}
|
{...passThroughProps}
|
||||||
@@ -29,7 +29,7 @@ const EditableHeading = function EditableHeading({
|
|||||||
value={value}
|
value={value}
|
||||||
required
|
required
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"absolute top-0 left-0 w-full cursor-pointer border-none bg-transparent p-0 align-top text-xl text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
|
"text-emphasis hover:text-default focus:text-emphasis absolute top-0 left-0 w-full cursor-pointer border-none bg-transparent p-0 align-top text-xl focus:outline-none focus:ring-0"
|
||||||
)}
|
)}
|
||||||
onFocus={(e) => {
|
onFocus={(e) => {
|
||||||
setIsEditing(true);
|
setIsEditing(true);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default function InfoBadge({ content }: { content: string }) {
|
|||||||
<>
|
<>
|
||||||
<Tooltip side="top" content={content}>
|
<Tooltip side="top" content={content}>
|
||||||
<span title={content}>
|
<span title={content}>
|
||||||
<FiInfo className="relative top-px left-1 right-1 mt-px h-4 w-4 text-gray-500" />
|
<FiInfo className="text-subtle relative top-px left-1 right-1 mt-px h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export default function LinkIconButton(props: LinkIconButtonProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
{...props}
|
{...props}
|
||||||
className="text-md flex items-center rounded-sm px-2 py-1 text-sm font-medium text-gray-700 hover:bg-gray-200 hover:text-gray-900">
|
className="text-md hover:bg-emphasis hover:text-emphasis text-default flex items-center rounded-sm px-2 py-1 text-sm font-medium">
|
||||||
<props.Icon className="h-4 w-4 text-gray-500 ltr:mr-2 rtl:ml-2" />
|
<props.Icon className="text-subtle h-4 w-4 ltr:mr-2 rtl:ml-2" />
|
||||||
{props.children}
|
{props.children}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default function ModalContainer(
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"inline-block w-full transform bg-white text-left align-bottom transition-all sm:align-middle",
|
"bg-default inline-block w-full transform text-left align-bottom transition-all sm:align-middle",
|
||||||
{
|
{
|
||||||
"sm:w-full sm:max-w-lg ": !props.wide,
|
"sm:w-full sm:max-w-lg ": !props.wide,
|
||||||
"sm:w-4xl sm:max-w-4xl": props.wide,
|
"sm:w-4xl sm:max-w-4xl": props.wide,
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ const PoweredByCal = () => {
|
|||||||
const isEmbed = useIsEmbed();
|
const isEmbed = useIsEmbed();
|
||||||
return (
|
return (
|
||||||
<div className={"p-2 text-center text-xs sm:text-right" + (isEmbed ? " max-w-3xl" : "")}>
|
<div className={"p-2 text-center text-xs sm:text-right" + (isEmbed ? " max-w-3xl" : "")}>
|
||||||
<Link
|
<Link href={POWERED_BY_URL} target="_blank" className="text-subtle opacity-50 hover:opacity-100">
|
||||||
href={POWERED_BY_URL}
|
|
||||||
target="_blank"
|
|
||||||
className="text-bookinglight opacity-50 hover:opacity-100 dark:text-white">
|
|
||||||
{t("powered_by")}{" "}
|
{t("powered_by")}{" "}
|
||||||
<img
|
<img
|
||||||
className="relative -mt-px inline h-[10px] w-auto dark:hidden"
|
className="relative -mt-px inline h-[10px] w-auto dark:hidden"
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export default function SettingInputContainer({
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="block sm:flex">
|
<div className="block sm:flex">
|
||||||
<div className="min-w-48 mb-4 sm:mb-0">
|
<div className="min-w-48 mb-4 sm:mb-0">
|
||||||
<label htmlFor={htmlFor} className="mt-1 flex text-sm font-medium text-gray-700">
|
<label htmlFor={htmlFor} className="text-default mt-1 flex text-sm font-medium">
|
||||||
<Icon className="mt-0.5 h-4 w-4 text-gray-500 ltr:mr-2 rtl:ml-2" />
|
<Icon className="text-subtle mt-0.5 h-4 w-4 ltr:mr-2 rtl:ml-2" />
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
|||||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||||
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, Input, Label } from "@calcom/ui";
|
import { Button, Dialog, DialogClose, DialogContent, Input, Label } from "@calcom/ui";
|
||||||
import { FiCheck, FiEdit2, FiExternalLink } from "@calcom/ui/components/icon";
|
import { FiCheck, FiEdit2, FiExternalLink } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
export enum UsernameChangeStatusEnum {
|
export enum UsernameChangeStatusEnum {
|
||||||
@@ -195,7 +195,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isInputUsernamePremium ? "border border-orange-400 " : "",
|
isInputUsernamePremium ? "border border-orange-400 " : "",
|
||||||
"hidden h-9 items-center rounded-l-md border border-r-0 border-gray-300 border-r-gray-300 bg-gray-50 px-3 text-sm text-gray-500 md:inline-flex"
|
"border-default bg-muted text-subtle hidden h-9 items-center rounded-l-md border border-r-0 border-r-gray-300 px-3 text-sm md:inline-flex"
|
||||||
)}>
|
)}>
|
||||||
{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/
|
{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/
|
||||||
</span>
|
</span>
|
||||||
@@ -216,7 +216,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
markAsError
|
markAsError
|
||||||
? "focus:shadow-0 focus:ring-shadow-0 border-red-500 focus:border-red-500 focus:outline-none"
|
? "focus:shadow-0 focus:ring-shadow-0 border-red-500 focus:border-red-500 focus:outline-none"
|
||||||
: "border-l-gray-300",
|
: "border-l-gray-300",
|
||||||
disabled ? "bg-gray-100 text-gray-400 focus:border-0" : ""
|
disabled ? "bg-subtle text-muted focus:border-0" : ""
|
||||||
)}
|
)}
|
||||||
value={inputUsernameValue}
|
value={inputUsernameValue}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
@@ -250,29 +250,30 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
{markAsError && <p className="mt-1 text-xs text-red-500">Username is already taken</p>}
|
{markAsError && <p className="mt-1 text-xs text-red-500">Username is already taken</p>}
|
||||||
|
|
||||||
<Dialog open={openDialogSaveUsername}>
|
<Dialog open={openDialogSaveUsername}>
|
||||||
<DialogContent>
|
<DialogContent
|
||||||
<div className="flex flex-row">
|
Icon={FiEdit2}
|
||||||
<div className="xs:hidden flex h-10 w-10 flex-shrink-0 justify-center rounded-full bg-[#FAFAFA]">
|
title={t("confirm_username_change_dialog_title")}
|
||||||
<FiEdit2 className="m-auto h-6 w-6" />
|
description={
|
||||||
</div>
|
<>
|
||||||
<div className="mb-4 w-full px-4 pt-1">
|
|
||||||
<DialogHeader title={t("confirm_username_change_dialog_title")} />
|
|
||||||
{usernameChangeCondition && usernameChangeCondition === UsernameChangeStatusEnum.UPGRADE && (
|
{usernameChangeCondition && usernameChangeCondition === UsernameChangeStatusEnum.UPGRADE && (
|
||||||
<p className="mb-4 text-sm text-gray-800">{t("change_username_standard_to_premium")}</p>
|
<p className="text-default mb-4 text-sm">{t("change_username_standard_to_premium")}</p>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
<div className="flex w-full flex-wrap rounded-sm bg-gray-100 py-3 text-sm">
|
}>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<div className="mb-4 w-full px-4 pt-1">
|
||||||
|
<div className="bg-subtle flex w-full flex-wrap rounded-sm py-3 text-sm">
|
||||||
<div className="flex-1 px-2">
|
<div className="flex-1 px-2">
|
||||||
<p className="text-gray-500">{t("current_username")}</p>
|
<p className="text-subtle">{t("current_username")}</p>
|
||||||
<p className="mt-1" data-testid="current-username">
|
<p className="text-emphasis mt-1" data-testid="current-username">
|
||||||
{currentUsername}
|
{currentUsername}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-6 flex-1">
|
<div className="ml-6 flex-1">
|
||||||
<p className="text-gray-500" data-testid="new-username">
|
<p className="text-subtle" data-testid="new-username">
|
||||||
{t("new_username")}
|
{t("new_username")}
|
||||||
</p>
|
</p>
|
||||||
<p>{inputUsernameValue}</p>
|
<p className="text-emphasis">{inputUsernameValue}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||||
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, TextField } from "@calcom/ui";
|
import { Button, Dialog, DialogClose, DialogContent, TextField } from "@calcom/ui";
|
||||||
import { FiCheck, FiEdit2 } from "@calcom/ui/components/icon";
|
import { FiCheck, FiEdit2 } from "@calcom/ui/components/icon";
|
||||||
|
|
||||||
interface ICustomUsernameProps {
|
interface ICustomUsernameProps {
|
||||||
@@ -79,7 +79,7 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
|
|
||||||
const ActionButtons = () => {
|
const ActionButtons = () => {
|
||||||
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
|
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
|
||||||
<div className="rlt:space-x-reverse mt-px flex flex-row space-x-2 ltr:ml-2 ltr:mr-2 rtl:ml-2 rtl:space-x-reverse">
|
<div className="rlt:space-x-reverse ms-2 me-2 mt-px flex flex-row space-x-2 rtl:space-x-reverse">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setOpenDialogSaveUsername(true)}
|
onClick={() => setOpenDialogSaveUsername(true)}
|
||||||
@@ -154,31 +154,25 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Dialog open={openDialogSaveUsername}>
|
<Dialog open={openDialogSaveUsername}>
|
||||||
<DialogContent>
|
<DialogContent type="confirmation" Icon={FiEdit2} title={t("confirm_username_change_dialog_title")}>
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div className="flex flex-row">
|
||||||
<div className="xs:hidden flex h-10 w-10 flex-shrink-0 justify-center rounded-full bg-[#FAFAFA]">
|
<div className="mb-4 w-full pt-1">
|
||||||
<FiEdit2 className="m-auto h-6 w-6" />
|
<div className="bg-subtle flex w-full flex-wrap rounded-sm py-3 text-sm">
|
||||||
</div>
|
|
||||||
<div className="mb-4 w-full px-4 pt-1">
|
|
||||||
<DialogHeader title={t("confirm_username_change_dialog_title")} />
|
|
||||||
|
|
||||||
<div className="flex w-full flex-wrap rounded-sm bg-gray-100 py-3 text-sm">
|
|
||||||
<div className="flex-1 px-2">
|
<div className="flex-1 px-2">
|
||||||
<p className="text-gray-500">{t("current_username")}</p>
|
<p className="text-subtle">{t("current_username")}</p>
|
||||||
<p className="mt-1" data-testid="current-username">
|
<p className="text-emphasis mt-1" data-testid="current-username">
|
||||||
{currentUsername}
|
{currentUsername}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="ml-6 flex-1">
|
||||||
<p className="text-gray-500" data-testid="new-username">
|
<p className="text-subtle" data-testid="new-username">
|
||||||
{t("new_username")}
|
{t("new_username")}
|
||||||
</p>
|
</p>
|
||||||
<p>{inputUsernameValue}</p>
|
<p className="text-emphasis">{inputUsernameValue}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-4 flex flex-row-reverse gap-x-2">
|
<div className="mt-4 flex flex-row-reverse gap-x-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(
|
|||||||
{React.createElement(
|
{React.createElement(
|
||||||
descriptionAsLabel ? "div" : "label",
|
descriptionAsLabel ? "div" : "label",
|
||||||
{
|
{
|
||||||
className: "flex text-sm font-medium text-gray-700",
|
className: "flex text-sm font-medium text-default",
|
||||||
...(!descriptionAsLabel
|
...(!descriptionAsLabel
|
||||||
? {
|
? {
|
||||||
htmlFor: rest.id,
|
htmlFor: rest.id,
|
||||||
@@ -40,7 +40,7 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(
|
|||||||
{
|
{
|
||||||
className: classNames(
|
className: classNames(
|
||||||
"relative flex items-start",
|
"relative flex items-start",
|
||||||
descriptionAsLabel ? "text-gray-700" : "text-gray-900"
|
descriptionAsLabel ? "text-default" : "text-emphasis"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
<>
|
<>
|
||||||
@@ -49,10 +49,10 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(
|
|||||||
{...rest}
|
{...rest}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-gray-300"
|
className="text-primary-600 focus:ring-primary-500 border-default h-4 w-4 rounded"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm ltr:ml-3 rtl:mr-3">{description}</span>
|
<span className="ms-3 text-sm">{description}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{informationIconText && <InfoBadge content={informationIconText} />}
|
{informationIconText && <InfoBadge content={informationIconText} />}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const CheckedSelect = ({
|
|||||||
{option.label}
|
{option.label}
|
||||||
<FiX
|
<FiX
|
||||||
onClick={() => props.onChange(value.filter((item) => item.value !== option.value))}
|
onClick={() => props.onChange(value.filter((item) => item.value !== option.value))}
|
||||||
className="float-right mt-0.5 h-5 w-5 cursor-pointer text-gray-500"
|
className="text-subtle float-right mt-0.5 h-5 w-5 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ export const DatePicker = ({ minDate, disabled, date, onDatesChange, className }
|
|||||||
return (
|
return (
|
||||||
<PrimitiveDatePicker
|
<PrimitiveDatePicker
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"focus:ring-primary-500 focus:border-primary-500 rounded-sm border border-gray-300 p-1 pl-2 text-sm",
|
"focus:ring-primary-500 focus:border-primary-500 border-default rounded-sm border p-1 pl-2 text-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
clearIcon={null}
|
clearIcon={null}
|
||||||
calendarIcon={<FiCalendar className="h-5 w-5 text-gray-500" />}
|
calendarIcon={<FiCalendar className="text-subtle h-5 w-5" />}
|
||||||
value={date}
|
value={date}
|
||||||
minDate={minDate}
|
minDate={minDate}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ export type GroupOptionType = GroupBase<LocationOption>;
|
|||||||
const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
|
const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{icon && <img src={icon} alt="cover" className="h-3.5 w-3.5" />}
|
{/* TODO: figure out a way to invert icons when in dark mode. We can't just
|
||||||
|
dark:invert due to google meet cal etc all breaking when we do this
|
||||||
|
*/}
|
||||||
|
{icon && <img src={icon} alt="cover" className="h-3.5 w-3.5 dark:hidden" />}
|
||||||
<span className={classNames("text-sm font-medium")}>{label}</span>
|
<span className={classNames("text-sm font-medium")}>{label}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -48,7 +51,7 @@ export default function LocationSelect(props: Props<LocationOption, false, Group
|
|||||||
<span>{e.label}</span>
|
<span>{e.label}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
formatGroupLabel={(e) => <p className="text-xs font-medium text-gray-600">{e.label}</p>}
|
formatGroupLabel={(e) => <p className="text-default text-xs font-medium">{e.label}</p>}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const MinutesField = forwardRef<HTMLInputElement, Props>(({ label, ...rest }, re
|
|||||||
<div className="block sm:flex">
|
<div className="block sm:flex">
|
||||||
{!!label && (
|
{!!label && (
|
||||||
<div className="min-w-48 mb-4 sm:mb-0">
|
<div className="min-w-48 mb-4 sm:mb-0">
|
||||||
<label htmlFor={rest.id} className="flex h-full items-center text-sm font-medium text-gray-700">
|
<label htmlFor={rest.id} className="text-default flex h-full items-center text-sm font-medium">
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,12 +23,12 @@ const MinutesField = forwardRef<HTMLInputElement, Props>(({ label, ...rest }, re
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
type="number"
|
type="number"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"block w-full rounded-sm border-gray-300 pl-2 pr-12 text-sm",
|
"border-default block w-full rounded-sm pl-2 pr-12 text-sm",
|
||||||
rest.className
|
rest.className
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
||||||
<span className="text-sm text-gray-500" id="duration">
|
<span className="text-subtle text-sm" id="duration">
|
||||||
mins
|
mins
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { appWithTranslation } from "next-i18next";
|
|||||||
import { ThemeProvider } from "next-themes";
|
import { ThemeProvider } from "next-themes";
|
||||||
import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app";
|
import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app";
|
||||||
import type { NextRouter } from "next/router";
|
import type { NextRouter } from "next/router";
|
||||||
import type { ComponentProps, ReactNode } from "react";
|
import { useRouter } from "next/router";
|
||||||
|
import type { ComponentProps, PropsWithChildren, ReactNode } from "react";
|
||||||
|
|
||||||
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
||||||
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
||||||
@@ -60,6 +61,51 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
|
|||||||
return <I18nextAdapter {...passedProps} />;
|
return <I18nextAdapter {...passedProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CalcomThemeProvider = (
|
||||||
|
props: PropsWithChildren<
|
||||||
|
WithNonceProps & { isThemeSupported?: boolean | ((arg: { router: NextRouter }) => boolean) }
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
// We now support the inverse of how we handled it in the past. Setting this to false will disable theme.
|
||||||
|
// undefined or true means we use system theme
|
||||||
|
const router = useRouter();
|
||||||
|
const isThemeSupported = (() => {
|
||||||
|
if (typeof props.isThemeSupported === "function") {
|
||||||
|
return props.isThemeSupported({ router: router });
|
||||||
|
}
|
||||||
|
if (typeof props.isThemeSupported === "undefined") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return props.isThemeSupported;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const forcedTheme = !isThemeSupported ? "light" : undefined;
|
||||||
|
// Use namespace of embed to ensure same namespaced embed are displayed with same theme. This allows different embeds on the same website to be themed differently
|
||||||
|
// One such example is our Embeds Demo and Testing page at http://localhost:3100
|
||||||
|
// Having `getEmbedNamespace` defined on window before react initializes the app, ensures that embedNamespace is available on the first mount and can be used as part of storageKey
|
||||||
|
const embedNamespace = typeof window !== "undefined" ? window.getEmbedNamespace() : null;
|
||||||
|
// If embedNamespace is not defined, we use the default storageKey -> The default storage key changs based on if we force light mode or not
|
||||||
|
// This is done to ensure that the default theme is light when we force light mode and as soon as you navigate to a page that is dark we dont need a hard refresh to change
|
||||||
|
const storageKey =
|
||||||
|
typeof embedNamespace === "string"
|
||||||
|
? `embed-theme-${embedNamespace}`
|
||||||
|
: !isThemeSupported
|
||||||
|
? "cal-light"
|
||||||
|
: "theme";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider
|
||||||
|
nonce={props.nonce}
|
||||||
|
enableColorScheme={false}
|
||||||
|
enableSystem={isThemeSupported}
|
||||||
|
forcedTheme={forcedTheme}
|
||||||
|
storageKey={storageKey}
|
||||||
|
attribute="class">
|
||||||
|
{props.children}
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function FeatureFlagsProvider({ children }: { children: React.ReactNode }) {
|
function FeatureFlagsProvider({ children }: { children: React.ReactNode }) {
|
||||||
const flags = useFlags();
|
const flags = useFlags();
|
||||||
return <FeatureProvider value={flags}>{children}</FeatureProvider>;
|
return <FeatureProvider value={flags}>{children}</FeatureProvider>;
|
||||||
@@ -69,16 +115,6 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||||||
const session = trpc.viewer.public.session.useQuery().data;
|
const session = trpc.viewer.public.session.useQuery().data;
|
||||||
// No need to have intercom on public pages - Good for Page Performance
|
// No need to have intercom on public pages - Good for Page Performance
|
||||||
const isPublicPage = usePublicPage();
|
const isPublicPage = usePublicPage();
|
||||||
const isThemeSupported =
|
|
||||||
typeof props.Component.isThemeSupported === "function"
|
|
||||||
? props.Component.isThemeSupported({ router: props.router })
|
|
||||||
: props.Component.isThemeSupported;
|
|
||||||
const forcedTheme = isThemeSupported ? undefined : "light";
|
|
||||||
// Use namespace of embed to ensure same namespaced embed are displayed with same theme. This allows different embeds on the same website to be themed differently
|
|
||||||
// One such example is our Embeds Demo and Testing page at http://localhost:3100
|
|
||||||
// Having `getEmbedNamespace` defined on window before react initializes the app, ensures that embedNamespace is available on the first mount and can be used as part of storageKey
|
|
||||||
const embedNamespace = typeof window !== "undefined" ? window.getEmbedNamespace() : null;
|
|
||||||
const storageKey = typeof embedNamespace === "string" ? `embed-theme-${embedNamespace}` : "theme";
|
|
||||||
|
|
||||||
const RemainingProviders = (
|
const RemainingProviders = (
|
||||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||||
@@ -86,16 +122,13 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
|||||||
<CustomI18nextProvider {...props}>
|
<CustomI18nextProvider {...props}>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
|
||||||
<ThemeProvider
|
<CalcomThemeProvider
|
||||||
nonce={props.pageProps.nonce}
|
nonce={props.pageProps.nonce}
|
||||||
enableColorScheme={false}
|
isThemeSupported={props.Component.isThemeSupported}>
|
||||||
storageKey={storageKey}
|
|
||||||
forcedTheme={forcedTheme}
|
|
||||||
attribute="class">
|
|
||||||
<FeatureFlagsProvider>
|
<FeatureFlagsProvider>
|
||||||
<MetaProvider>{props.children}</MetaProvider>
|
<MetaProvider>{props.children}</MetaProvider>
|
||||||
</FeatureFlagsProvider>
|
</FeatureFlagsProvider>
|
||||||
</ThemeProvider>
|
</CalcomThemeProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</CustomI18nextProvider>
|
</CustomI18nextProvider>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@calcom/web",
|
"name": "@calcom/web",
|
||||||
"version": "2.7.7",
|
"version": "2.7.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "ANALYZE=true next build",
|
"analyze": "ANALYZE=true next build",
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"msw": "^0.42.3",
|
"msw": "^0.42.3",
|
||||||
"postcss": "^8.4.18",
|
"postcss": "^8.4.18",
|
||||||
"tailwindcss": "^3.2.1",
|
"tailwindcss": "^3.3.1",
|
||||||
"ts-jest": "^28.0.8",
|
"ts-jest": "^28.0.8",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
|
|||||||
+46
-44
@@ -3,7 +3,7 @@ import Link from "next/link";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { COMPANY_NAME, DEVELOPER_DOCS, DOCS_URL, JOIN_SLACK, WEBSITE_URL } from "@calcom/lib/constants";
|
import { DOCS_URL, JOIN_SLACK, WEBSITE_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { HeadSeo } from "@calcom/ui";
|
import { HeadSeo } from "@calcom/ui";
|
||||||
import { FiBookOpen, FiCheck, FiChevronRight, FiFileText } from "@calcom/ui/components/icon";
|
import { FiBookOpen, FiCheck, FiChevronRight, FiFileText } from "@calcom/ui/components/icon";
|
||||||
@@ -88,21 +88,21 @@ export default function Custom404() {
|
|||||||
noindex: true,
|
noindex: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="min-h-screen bg-white px-4" data-testid="404-page">
|
<div className="bg-default min-h-screen px-4" data-testid="404-page">
|
||||||
<main className="mx-auto max-w-xl pt-16 pb-6 sm:pt-24">
|
<main className="mx-auto max-w-xl pt-16 pb-6 sm:pt-24">
|
||||||
{isSignup && process.env.NEXT_PUBLIC_WEBAPP_URL !== "https://app.cal.com" ? (
|
{isSignup && process.env.NEXT_PUBLIC_WEBAPP_URL !== "https://app.cal.com" ? (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">
|
<p className="text-emphasis text-sm font-semibold uppercase tracking-wide">
|
||||||
{t("missing_license")}
|
{t("missing_license")}
|
||||||
</p>
|
</p>
|
||||||
<h1 className="font-cal mt-2 text-3xl font-extrabold text-gray-900">
|
<h1 className="font-cal text-emphasis mt-2 text-3xl font-extrabold">
|
||||||
{t("signup_requires")}
|
{t("signup_requires")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-4">{t("signup_requires_description", { companyName: COMPANY_NAME })}</p>
|
<p className="mt-4">{t("signup_requires_description", { companyName: "Cal.com" })}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-12">
|
<div className="mt-12">
|
||||||
<h2 className="text-sm font-semibold uppercase tracking-wide text-gray-500">
|
<h2 className="text-subtle text-sm font-semibold uppercase tracking-wide">
|
||||||
{t("next_steps")}
|
{t("next_steps")}
|
||||||
</h2>
|
</h2>
|
||||||
<ul role="list" className="mt-4">
|
<ul role="list" className="mt-4">
|
||||||
@@ -116,44 +116,44 @@ export default function Custom404() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="focus:outline-none">
|
<span className="focus:outline-none">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
{t("acquire_commercial_license")}
|
{t("acquire_commercial_license")}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{t("the_infrastructure_plan")}</p>
|
<p className="text-subtle text-base">{t("the_infrastructure_plan")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul role="list" className="divide-y divide-gray-200 border-gray-200">
|
<ul role="list" className="border-subtle divide-subtle divide-y">
|
||||||
<li className="px-4 py-2">
|
<li className="px-4 py-2">
|
||||||
<Link
|
<Link
|
||||||
href={`${DEVELOPER_DOCS}/self-hosting/installation`}
|
href="https://cal.com/self-hosting/installation"
|
||||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
<span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg">
|
||||||
<FiFileText className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
<FiFileText className="text-default h-6 w-6" aria-hidden="true" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
{t("prisma_studio_tip")}
|
{t("prisma_studio_tip")}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{t("prisma_studio_tip_description")}</p>
|
<p className="text-subtle text-base">{t("prisma_studio_tip_description")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@@ -162,7 +162,7 @@ export default function Custom404() {
|
|||||||
href={JOIN_SLACK}
|
href={JOIN_SLACK}
|
||||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
<span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg">
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 2447.6 2452.5"
|
viewBox="0 0 2447.6 2452.5"
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
@@ -189,16 +189,16 @@ export default function Custom404() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
Slack
|
Slack
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{t("join_our_community")}</p>
|
<p className="text-subtle text-base">{t("join_our_community")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -206,7 +206,7 @@ export default function Custom404() {
|
|||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<Link
|
<Link
|
||||||
href={`${WEBSITE_URL}/enterprise`}
|
href={`${WEBSITE_URL}/enterprise`}
|
||||||
className="text-base font-medium text-black hover:text-gray-500">
|
className="hover:text-subtle text-emphasis text-base font-medium">
|
||||||
{t("contact_sales")}
|
{t("contact_sales")}
|
||||||
<span aria-hidden="true"> →</span>
|
<span aria-hidden="true"> →</span>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -216,8 +216,10 @@ export default function Custom404() {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">{t("error_404")}</p>
|
<p className="text-emphasis text-sm font-semibold uppercase tracking-wide">
|
||||||
<h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 sm:text-5xl">
|
{t("error_404")}
|
||||||
|
</p>
|
||||||
|
<h1 className="font-cal text-emphasis mt-2 text-4xl font-extrabold sm:text-5xl">
|
||||||
{isSuccessPage ? "Booking not found" : t("page_doesnt_exist")}
|
{isSuccessPage ? "Booking not found" : t("page_doesnt_exist")}
|
||||||
</h1>
|
</h1>
|
||||||
{isSubpage ? (
|
{isSubpage ? (
|
||||||
@@ -242,7 +244,7 @@ export default function Custom404() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-12">
|
<div className="mt-12">
|
||||||
<h2 className="text-sm font-semibold uppercase tracking-wide text-gray-500">
|
<h2 className="text-subtle text-sm font-semibold uppercase tracking-wide">
|
||||||
{t("popular_pages")}
|
{t("popular_pages")}
|
||||||
</h2>
|
</h2>
|
||||||
{!isSubpage && isCalcom && (
|
{!isSubpage && isCalcom && (
|
||||||
@@ -259,46 +261,46 @@ export default function Custom404() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="focus:outline-none">
|
<span className="focus:outline-none">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
{t("register")} <strong className="text-green-500">{username}</strong>
|
{t("register")} <strong className="text-green-500">{username}</strong>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{t("claim_username_and_schedule_events")}</p>
|
<p className="text-subtle text-base">{t("claim_username_and_schedule_events")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ul role="list" className="mt-4 divide-y divide-gray-200 border-gray-200">
|
<ul role="list" className="border-subtle divide-subtle mt-4 divide-y">
|
||||||
{links.map((link, linkIdx) => (
|
{links.map((link, linkIdx) => (
|
||||||
<li key={linkIdx} className="px-4 py-2">
|
<li key={linkIdx} className="px-4 py-2">
|
||||||
<Link
|
<Link
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
<span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg">
|
||||||
<link.icon className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
<link.icon className="text-default h-6 w-6" aria-hidden="true" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
{link.title}
|
{link.title}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{link.description}</p>
|
<p className="text-subtle text-base">{link.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@@ -308,7 +310,7 @@ export default function Custom404() {
|
|||||||
href={JOIN_SLACK}
|
href={JOIN_SLACK}
|
||||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
<span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg">
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 2447.6 2452.5"
|
viewBox="0 0 2447.6 2452.5"
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
@@ -335,22 +337,22 @@ export default function Custom404() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-base font-medium text-gray-900">
|
<h3 className="text-emphasis text-base font-medium">
|
||||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
|
||||||
<span className="absolute inset-0" aria-hidden="true" />
|
<span className="absolute inset-0" aria-hidden="true" />
|
||||||
Slack
|
Slack
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">{t("join_our_community")}</p>
|
<p className="text-subtle text-base">{t("join_our_community")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<FiChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<Link href="/" className="text-base font-medium text-black hover:text-gray-500">
|
<Link href="/" className="hover:text-subtle text-emphasis text-base font-medium">
|
||||||
{t("or_go_back_home")}
|
{t("or_go_back_home")}
|
||||||
<span aria-hidden="true"> →</span>
|
<span aria-hidden="true"> →</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -11,24 +11,24 @@ export default function Error500() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-gray-100">
|
<div className="bg-subtle flex h-screen">
|
||||||
<Head>
|
<Head>
|
||||||
<title>Something unexpected occurred | {APP_NAME}</title>
|
<title>Something unexpected occurred | {APP_NAME}</title>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<div className="rtl: m-auto rounded-md bg-white p-10 text-right ltr:text-left">
|
<div className="rtl: bg-default m-auto rounded-md p-10 text-right ltr:text-left">
|
||||||
<h1 className="font-cal text-6xl text-black">500</h1>
|
<h1 className="font-cal text-emphasis text-6xl">500</h1>
|
||||||
<h2 className="mt-6 text-2xl font-medium text-black">It's not you, it's us.</h2>
|
<h2 className="text-emphasis mt-6 text-2xl font-medium">It's not you, it's us.</h2>
|
||||||
<p className="mt-4 mb-6 max-w-2xl text-sm text-gray-600">
|
<p className="text-default mt-4 mb-6 max-w-2xl text-sm">
|
||||||
Something went wrong on our end. Get in touch with our support team, and we’ll get it fixed right
|
Something went wrong on our end. Get in touch with our support team, and we’ll get it fixed right
|
||||||
away for you.
|
away for you.
|
||||||
</p>
|
</p>
|
||||||
{router.query.error && (
|
{router.query.error && (
|
||||||
<div className="mb-8 flex flex-col">
|
<div className="mb-8 flex flex-col">
|
||||||
<p className="mb-4 max-w-2xl text-sm text-gray-600">
|
<p className="text-default mb-4 max-w-2xl text-sm">
|
||||||
Please provide the following text when contacting support to better help you:
|
Please provide the following text when contacting support to better help you:
|
||||||
</p>
|
</p>
|
||||||
<pre className="w-full max-w-2xl whitespace-normal break-words rounded-md bg-gray-200 p-4 text-gray-900">
|
<pre className="bg-emphasis text-emphasis w-full max-w-2xl whitespace-normal break-words rounded-md p-4">
|
||||||
{router.query.error}
|
{router.query.error}
|
||||||
<br />
|
<br />
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
+20
-37
@@ -14,7 +14,6 @@ import {
|
|||||||
} from "@calcom/embed-core/embed-iframe";
|
} from "@calcom/embed-core/embed-iframe";
|
||||||
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
||||||
import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage";
|
import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage";
|
||||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import defaultEvents, {
|
import defaultEvents, {
|
||||||
getDynamicEventDescription,
|
getDynamicEventDescription,
|
||||||
@@ -48,9 +47,9 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
|
|
||||||
const groupEventTypes = props.users.some((user) => !user.allowDynamicBooking) ? (
|
const groupEventTypes = props.users.some((user) => !user.allowDynamicBooking) ? (
|
||||||
<div className="space-y-6" data-testid="event-types">
|
<div className="space-y-6" data-testid="event-types">
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border ">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">{" " + t("unavailable")}</h2>
|
<h2 className="font-cal text-default mb-2 text-3xl">{" " + t("unavailable")}</h2>
|
||||||
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled") as string}</p>
|
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled") as string}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,14 +59,14 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
{eventTypes.map((type, index) => (
|
{eventTypes.map((type, index) => (
|
||||||
<li
|
<li
|
||||||
key={index}
|
key={index}
|
||||||
className="dark:bg-darkgray-100 dark:border-darkgray-300 group relative border-b border-gray-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50">
|
className=" border-subtle bg-default hover:bg-muted group relative border-b first:rounded-t-md last:rounded-b-md last:border-b-0">
|
||||||
<FiArrowRight className="absolute right-3 top-3 h-4 w-4 text-black opacity-0 transition-opacity group-hover:opacity-100 dark:text-white" />
|
<FiArrowRight className="text-emphasis absolute right-3 top-3 h-4 w-4 opacity-0 transition-opacity group-hover:opacity-100" />
|
||||||
<Link
|
<Link
|
||||||
href={getUsernameSlugLink({ users: props.users, slug: type.slug })}
|
href={getUsernameSlugLink({ users: props.users, slug: type.slug })}
|
||||||
className="flex justify-between px-6 py-4"
|
className="flex justify-between px-6 py-4"
|
||||||
data-testid="event-type-link">
|
data-testid="event-type-link">
|
||||||
<div className="flex-shrink">
|
<div className="flex-shrink">
|
||||||
<p className="dark:text-darkgray-700 text-sm font-semibold text-gray-900">{type.title}</p>
|
<p className=" text-emphasis text-sm font-semibold">{type.title}</p>
|
||||||
<EventTypeDescription className="text-sm" eventType={type} />
|
<EventTypeDescription className="text-sm" eventType={type} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 self-center">
|
<div className="mt-1 self-center">
|
||||||
@@ -118,53 +117,39 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
: [{ username: `${user.username}`, name: `${user.name}` }],
|
: [{ username: `${user.username}`, name: `${user.name}` }],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
|
|
||||||
|
|
||||||
<div
|
<div className={classNames(shouldAlignCentrally ? "mx-auto" : "", isEmbed ? "max-w-3xl" : "")}>
|
||||||
className={classNames(
|
|
||||||
shouldAlignCentrally ? "mx-auto" : "",
|
|
||||||
isEmbed ? "max-w-3xl" : "",
|
|
||||||
"dark:bg-darkgray-50"
|
|
||||||
)}>
|
|
||||||
<main
|
<main
|
||||||
className={classNames(
|
className={classNames(
|
||||||
shouldAlignCentrally ? "mx-auto" : "",
|
shouldAlignCentrally ? "mx-auto" : "",
|
||||||
isEmbed
|
isEmbed ? " border-bookinglightest bg-default rounded-md border" : "",
|
||||||
? " border-bookinglightest dark:bg-darkgray-50 rounded-md border bg-white sm:dark:border-gray-600"
|
|
||||||
: "",
|
|
||||||
"max-w-3xl py-24 px-4"
|
"max-w-3xl py-24 px-4"
|
||||||
)}>
|
)}>
|
||||||
{isSingleUser && ( // When we deal with a single user, not dynamic group
|
{isSingleUser && ( // When we deal with a single user, not dynamic group
|
||||||
<div className="mb-8 text-center">
|
<div className="mb-8 text-center">
|
||||||
<Avatar imageSrc={user.avatar} size="xl" alt={nameOrUsername} />
|
<Avatar imageSrc={user.avatar} size="xl" alt={nameOrUsername} />
|
||||||
<h1 className="font-cal mb-1 text-3xl text-gray-900 dark:text-white">
|
<h1 className="font-cal text-emphasis mb-1 text-3xl">
|
||||||
{nameOrUsername}
|
{nameOrUsername}
|
||||||
{user.verified && (
|
{user.verified && <BadgeCheckIcon className=" mx-1 -mt-1 inline h-6 w-6 text-blue-500" />}
|
||||||
<BadgeCheckIcon className="mx-1 -mt-1 inline h-6 w-6 text-blue-500 dark:text-white" />
|
|
||||||
)}
|
|
||||||
</h1>
|
</h1>
|
||||||
{!isBioEmpty && (
|
{!isBioEmpty && (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className=" dark:text-darkgray-600 text-sm text-gray-500 [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
className=" text-subtle text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
||||||
dangerouslySetInnerHTML={{ __html: props.safeBio }}
|
dangerouslySetInnerHTML={{ __html: props.safeBio }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames("rounded-md ", !isEventListEmpty && "border-subtle border")}
|
||||||
"rounded-md ",
|
|
||||||
!isEventListEmpty && "dark:border-darkgray-300 border border-gray-200"
|
|
||||||
)}
|
|
||||||
data-testid="event-types">
|
data-testid="event-types">
|
||||||
{user.away ? (
|
{user.away ? (
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border ">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">
|
<h2 className="font-cal text-default mb-2 text-3xl">😴{" " + t("user_away")}</h2>
|
||||||
😴{" " + t("user_away")}
|
|
||||||
</h2>
|
|
||||||
<p className="mx-auto max-w-md">{t("user_away_description") as string}</p>
|
<p className="mx-auto max-w-md">{t("user_away_description") as string}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,8 +160,8 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
<div
|
<div
|
||||||
key={type.id}
|
key={type.id}
|
||||||
style={{ display: "flex", ...eventTypeListItemEmbedStyles }}
|
style={{ display: "flex", ...eventTypeListItemEmbedStyles }}
|
||||||
className="dark:bg-darkgray-100 dark:hover:bg-darkgray-200 dark:border-darkgray-300 group relative border-b border-gray-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50">
|
className=" border-subtle bg-default hover:bg-muted group relative border-b first:rounded-t-md last:rounded-b-md last:border-b-0">
|
||||||
<FiArrowRight className="absolute right-4 top-4 h-4 w-4 text-black opacity-0 transition-opacity group-hover:opacity-100 dark:text-white" />
|
<FiArrowRight className="text-emphasis absolute right-4 top-4 h-4 w-4 opacity-0 transition-opacity group-hover:opacity-100" />
|
||||||
{/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */}
|
{/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */}
|
||||||
<div className="block w-full p-5">
|
<div className="block w-full p-5">
|
||||||
<Link
|
<Link
|
||||||
@@ -193,9 +178,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
}}
|
}}
|
||||||
data-testid="event-type-link">
|
data-testid="event-type-link">
|
||||||
<div className="flex flex-wrap items-center">
|
<div className="flex flex-wrap items-center">
|
||||||
<h2 className="dark:text-darkgray-700 pr-2 text-sm font-semibold text-gray-700">
|
<h2 className=" text-default pr-2 text-sm font-semibold">{type.title}</h2>
|
||||||
{type.title}
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<EventTypeDescription eventType={type} />
|
<EventTypeDescription eventType={type} />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -204,6 +187,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isEventListEmpty && <EmptyPage name={user.name ?? "User"} />}
|
{isEventListEmpty && <EmptyPage name={user.name ?? "User"} />}
|
||||||
</main>
|
</main>
|
||||||
<Toaster position="bottom-right" />
|
<Toaster position="bottom-right" />
|
||||||
@@ -211,7 +195,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
User.isThemeSupported = true;
|
|
||||||
|
|
||||||
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ export default function Type(props: AvailabilityPageProps) {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
return props.away ? (
|
return props.away ? (
|
||||||
<div className="h-screen dark:bg-gray-900">
|
<div className="dark:bg-inverted h-screen">
|
||||||
<main className="mx-auto max-w-3xl px-4 py-24">
|
<main className="mx-auto max-w-3xl px-4 py-24">
|
||||||
<div className="space-y-6" data-testid="event-types">
|
<div className="space-y-6" data-testid="event-types">
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted dark:text-inverted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">
|
<h2 className="font-cal dark:text-inverted text-emphasis600 mb-2 text-3xl">
|
||||||
😴{" " + t("user_away")}
|
😴{" " + t("user_away")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mx-auto max-w-md">{t("user_away_description")}</p>
|
<p className="mx-auto max-w-md">{t("user_away_description")}</p>
|
||||||
@@ -39,8 +39,8 @@ export default function Type(props: AvailabilityPageProps) {
|
|||||||
<main className="mx-auto max-w-3xl px-4 py-24">
|
<main className="mx-auto max-w-3xl px-4 py-24">
|
||||||
<div className="space-y-6" data-testid="event-types">
|
<div className="space-y-6" data-testid="event-types">
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted dark:text-inverted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">
|
<h2 className="font-cal dark:text-inverted text-emphasis600 mb-2 text-3xl">
|
||||||
{" " + t("unavailable")}
|
{" " + t("unavailable")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled")}</p>
|
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled")}</p>
|
||||||
@@ -54,8 +54,6 @@ export default function Type(props: AvailabilityPageProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type.isThemeSupported = true;
|
|
||||||
|
|
||||||
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
const paramsSchema = z.object({ type: z.string(), user: z.string() });
|
||||||
async function getUserPageProps(context: GetStaticPropsContext) {
|
async function getUserPageProps(context: GetStaticPropsContext) {
|
||||||
// load server side dependencies
|
// load server side dependencies
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import {
|
|||||||
getGroupName,
|
getGroupName,
|
||||||
getUsernameList,
|
getUsernameList,
|
||||||
} from "@calcom/lib/defaultEvents";
|
} from "@calcom/lib/defaultEvents";
|
||||||
|
import getBooking from "@calcom/lib/getBooking";
|
||||||
|
import type { GetBookingType } from "@calcom/lib/getBooking";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||||
import prisma, { bookEventTypeSelect } from "@calcom/prisma";
|
import prisma, { bookEventTypeSelect } from "@calcom/prisma";
|
||||||
@@ -22,8 +24,6 @@ import {
|
|||||||
userMetadata as userMetadataSchema,
|
userMetadata as userMetadataSchema,
|
||||||
} from "@calcom/prisma/zod-utils";
|
} from "@calcom/prisma/zod-utils";
|
||||||
|
|
||||||
import type { GetBookingType } from "@lib/getBooking";
|
|
||||||
import getBooking from "@lib/getBooking";
|
|
||||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
import BookingPage from "@components/booking/pages/BookingPage";
|
import BookingPage from "@components/booking/pages/BookingPage";
|
||||||
@@ -35,12 +35,12 @@ export type BookPageProps = inferSSRProps<typeof getServerSideProps>;
|
|||||||
export default function Book(props: BookPageProps) {
|
export default function Book(props: BookPageProps) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return props.away ? (
|
return props.away ? (
|
||||||
<div className="h-screen dark:bg-gray-900">
|
<div className="dark:bg-inverted h-screen">
|
||||||
<main className="mx-auto max-w-3xl px-4 py-24">
|
<main className="mx-auto max-w-3xl px-4 py-24">
|
||||||
<div className="space-y-6" data-testid="event-types">
|
<div className="space-y-6" data-testid="event-types">
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted dark:text-inverted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">
|
<h2 className="font-cal dark:text-inverted text-default mb-2 text-3xl">
|
||||||
😴{" " + t("user_away")}
|
😴{" " + t("user_away")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mx-auto max-w-md">{t("user_away_description")}</p>
|
<p className="mx-auto max-w-md">{t("user_away_description")}</p>
|
||||||
@@ -50,12 +50,12 @@ export default function Book(props: BookPageProps) {
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
) : props.isDynamicGroupBooking && !props.profile.allowDynamicBooking ? (
|
) : props.isDynamicGroupBooking && !props.profile.allowDynamicBooking ? (
|
||||||
<div className="h-screen dark:bg-gray-900">
|
<div className="dark:bg-inverted h-screen">
|
||||||
<main className="mx-auto max-w-3xl px-4 py-24">
|
<main className="mx-auto max-w-3xl px-4 py-24">
|
||||||
<div className="space-y-6" data-testid="event-types">
|
<div className="space-y-6" data-testid="event-types">
|
||||||
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
<div className="overflow-hidden rounded-sm border dark:border-gray-900">
|
||||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
<div className="text-muted dark:text-inverted p-8 text-center">
|
||||||
<h2 className="font-cal mb-2 text-3xl text-gray-600 dark:text-white">
|
<h2 className="font-cal dark:text-inverted text-default mb-2 text-3xl">
|
||||||
{" " + t("unavailable")}
|
{" " + t("unavailable")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled")}</p>
|
<p className="mx-auto max-w-md">{t("user_dynamic_booking_disabled")}</p>
|
||||||
@@ -69,8 +69,6 @@ export default function Book(props: BookPageProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Book.isThemeSupported = true;
|
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
bookingUid: z.string().optional(),
|
bookingUid: z.string().optional(),
|
||||||
count: z.coerce.number().optional(),
|
count: z.coerce.number().optional(),
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export const getStaticProps: GetStaticProps<
|
|||||||
revalidate: 1,
|
revalidate: 1,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let message = "Unknown error while fetching calendarƒ";
|
let message = "Unknown error while fetching calendar";
|
||||||
if (error instanceof Error) message = error.message;
|
if (error instanceof Error) message = error.message;
|
||||||
console.error(error, message);
|
console.error(error, message);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ class MyDocument extends Document<Props> {
|
|||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
||||||
<meta name="msapplication-TileColor" content="#ff0000" />
|
<meta name="msapplication-TileColor" content="#ff0000" />
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="var(--cal-bg)" />
|
||||||
<Script src="/embed-init-iframe.js" strategy="beforeInteractive" />
|
<Script src="/embed-init-iframe.js" strategy="beforeInteractive" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
className="dark:bg-darkgray-50 desktop-transparent bg-gray-100 antialiased"
|
className="dark:bg-darkgray-50 desktop-transparent bg-subtle antialiased"
|
||||||
style={
|
style={
|
||||||
isEmbed
|
isEmbed
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
|||||||
|
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { sendOrganizerRequestReminderEmail } from "@calcom/emails";
|
import { sendOrganizerRequestReminderEmail } from "@calcom/emails";
|
||||||
|
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
|
||||||
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
||||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||||
@@ -48,8 +49,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
eventType: {
|
eventType: {
|
||||||
select: {
|
select: {
|
||||||
recurringEvent: true,
|
recurringEvent: true,
|
||||||
|
bookingFields: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
responses: true,
|
||||||
uid: true,
|
uid: true,
|
||||||
destinationCalendar: true,
|
destinationCalendar: true,
|
||||||
},
|
},
|
||||||
@@ -96,6 +99,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
title: booking.title,
|
title: booking.title,
|
||||||
description: booking.description || undefined,
|
description: booking.description || undefined,
|
||||||
customInputs: isPrismaObjOrUndefined(booking.customInputs),
|
customInputs: isPrismaObjOrUndefined(booking.customInputs),
|
||||||
|
...getCalEventResponses({
|
||||||
|
bookingFields: booking.eventType?.bookingFields ?? null,
|
||||||
|
booking,
|
||||||
|
}),
|
||||||
location: booking.location ?? "",
|
location: booking.location ?? "",
|
||||||
startTime: booking.startTime.toISOString(),
|
startTime: booking.startTime.toISOString(),
|
||||||
endTime: booking.endTime.toISOString(),
|
endTime: booking.endTime.toISOString(),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default function SetupInformation(props: InferGetStaticPropsType<typeof g
|
|||||||
const { status } = useSession();
|
const { status } = useSession();
|
||||||
|
|
||||||
if (status === "loading") {
|
if (status === "loading") {
|
||||||
return <div className="absolute z-50 flex h-screen w-full items-center bg-gray-200" />;
|
return <div className="bg-emphasis absolute z-50 flex h-screen w-full items-center" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === "unauthenticated") {
|
if (status === "unauthenticated") {
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
|||||||
<>
|
<>
|
||||||
<Link
|
<Link
|
||||||
href="/apps"
|
href="/apps"
|
||||||
className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
className="text-emphasis inline-flex items-center justify-start gap-1 rounded-sm py-2">
|
||||||
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
||||||
</Link>
|
</Link>
|
||||||
{category && (
|
{category && (
|
||||||
<span className="gap-1 text-gray-600">
|
<span className="text-default gap-1">
|
||||||
<span> / </span>
|
<span> / </span>
|
||||||
{t("category_apps", { category: category[0].toUpperCase() + category?.slice(1) })}
|
{t("category_apps", { category: category[0].toUpperCase() + category?.slice(1) })}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
|||||||
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
||||||
<Link
|
<Link
|
||||||
href="/apps"
|
href="/apps"
|
||||||
className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
className="text-emphasis inline-flex items-center justify-start gap-1 rounded-sm py-2">
|
||||||
<FiArrowLeft className="h-4 w-4" />
|
<FiArrowLeft className="h-4 w-4" />
|
||||||
{isLocaleReady ? t("app_store") : <SkeletonText className="h-6 w-24" />}{" "}
|
{isLocaleReady ? t("app_store") : <SkeletonText className="h-6 w-24" />}{" "}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -27,10 +27,10 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
|||||||
key={category.name}
|
key={category.name}
|
||||||
href={"/apps/categories/" + category.name}
|
href={"/apps/categories/" + category.name}
|
||||||
data-testid={`app-store-category-${category.name}`}
|
data-testid={`app-store-category-${category.name}`}
|
||||||
className="relative flex rounded-sm bg-gray-100 px-6 py-4 sm:block">
|
className="bg-subtle relative flex rounded-sm px-6 py-4 sm:block">
|
||||||
<div className="self-center">
|
<div className="self-center">
|
||||||
<h3 className="font-medium capitalize">{category.name}</h3>
|
<h3 className="font-medium capitalize">{category.name}</h3>
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-subtle text-sm">
|
||||||
{t("number_apps", { count: category.count })}{" "}
|
{t("number_apps", { count: category.count })}{" "}
|
||||||
<FiArrowRight className="inline-block h-4 w-4" />
|
<FiArrowRight className="inline-block h-4 w-4" />
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ function AppsSearch({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
className="!border-gray-100 bg-gray-100 !pl-0 focus:!ring-offset-0"
|
className="bg-subtle !border-muted !pl-0 focus:!ring-offset-0"
|
||||||
addOnLeading={<FiSearch className="h-4 w-4 text-gray-500" />}
|
addOnLeading={<FiSearch className="text-subtle h-4 w-4" />}
|
||||||
addOnClassname="!border-gray-100"
|
addOnClassname="!border-muted"
|
||||||
containerClassName={classNames("focus:!ring-offset-0", className)}
|
containerClassName={classNames("focus:!ring-offset-0", className)}
|
||||||
type="search"
|
type="search"
|
||||||
autoComplete="false"
|
autoComplete="false"
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ const IntegrationsContainer = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border border-gray-200 p-7">
|
<div className="border-subtle rounded-md border p-7">
|
||||||
<ShellSubHeading
|
<ShellSubHeading
|
||||||
title={t(variant || "other")}
|
title={t(variant || "other")}
|
||||||
subtitle={t(`installed_app_${variant || "other"}_description`)}
|
subtitle={t(`installed_app_${variant || "other"}_description`)}
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ export default function Error() {
|
|||||||
return (
|
return (
|
||||||
<AuthContainer title="" description="">
|
<AuthContainer title="" description="">
|
||||||
<div>
|
<div>
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
|
<div className="bg-error mx-auto flex h-12 w-12 items-center justify-center rounded-full">
|
||||||
<FiX className="h-6 w-6 text-red-600" />
|
<FiX className="h-6 w-6 text-red-600" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-center sm:mt-5">
|
<div className="mt-3 text-center sm:mt-5">
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
<h3 className="text-emphasis text-lg font-medium leading-6" id="modal-title">
|
||||||
{error}
|
{error}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-gray-500">{errorMsg}</p>
|
<p className="text-subtle text-sm">{errorMsg}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||||||
<>
|
<>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">
|
<h2 className="font-cal text-emphasis mt-6 text-center text-3xl font-extrabold">
|
||||||
{t("password_updated")}
|
{t("password_updated")}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,8 +77,8 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||||||
<>
|
<>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="font-cal mt-6 text-center text-3xl font-extrabold text-gray-900">{t("whoops")}</h2>
|
<h2 className="font-cal text-emphasis mt-6 text-center text-3xl font-extrabold">{t("whoops")}</h2>
|
||||||
<h2 className="text-center text-3xl font-extrabold text-gray-900">{t("request_is_expired")}</h2>
|
<h2 className="text-emphasis text-center text-3xl font-extrabold">{t("request_is_expired")}</h2>
|
||||||
</div>
|
</div>
|
||||||
<p>{t("request_is_expired_instructions")}</p>
|
<p>{t("request_is_expired_instructions")}</p>
|
||||||
<Link href="/auth/forgot-password" passHref legacyBehavior>
|
<Link href="/auth/forgot-password" passHref legacyBehavior>
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
|||||||
footerText={
|
footerText={
|
||||||
!success && (
|
!success && (
|
||||||
<>
|
<>
|
||||||
<Link href="/auth/login" className="font-medium text-gray-900">
|
<Link href="/auth/login" className="text-emphasis font-medium">
|
||||||
{t("back_to_signin")}
|
{t("back_to_signin")}
|
||||||
</Link>
|
</Link>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { GetServerSidePropsContext } from "next";
|
|||||||
import { getCsrfToken, signIn } from "next-auth/react";
|
import { getCsrfToken, signIn } from "next-auth/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import type { CSSProperties } from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
import { FaGoogle } from "react-icons/fa";
|
import { FaGoogle } from "react-icons/fa";
|
||||||
@@ -124,7 +125,15 @@ export default function Login({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"--cal-brand": "#111827",
|
||||||
|
"--cal-brand-emphasis": "#101010",
|
||||||
|
"--cal-brand-text": "white",
|
||||||
|
"--cal-brand-subtle": "#9CA3AF",
|
||||||
|
} as CSSProperties
|
||||||
|
}>
|
||||||
<AuthContainer
|
<AuthContainer
|
||||||
title={t("login")}
|
title={t("login")}
|
||||||
description={t("login")}
|
description={t("login")}
|
||||||
@@ -159,7 +168,7 @@ export default function Login({
|
|||||||
<Link
|
<Link
|
||||||
href="/auth/forgot-password"
|
href="/auth/forgot-password"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className="text-sm font-medium text-gray-600">
|
className="text-default text-sm font-medium">
|
||||||
{t("forgot")}
|
{t("forgot")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,7 +196,7 @@ export default function Login({
|
|||||||
</form>
|
</form>
|
||||||
{!twoFactorRequired && (
|
{!twoFactorRequired && (
|
||||||
<>
|
<>
|
||||||
{(isGoogleLoginEnabled || isSAMLLoginEnabled) && <hr className="my-8" />}
|
{(isGoogleLoginEnabled || isSAMLLoginEnabled) && <hr className="border-subtle my-8" />}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{isGoogleLoginEnabled && (
|
{isGoogleLoginEnabled && (
|
||||||
<Button
|
<Button
|
||||||
@@ -215,7 +224,7 @@ export default function Login({
|
|||||||
</FormProvider>
|
</FormProvider>
|
||||||
</AuthContainer>
|
</AuthContainer>
|
||||||
<AddToHomescreen />
|
<AddToHomescreen />
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,4 +301,6 @@ const _getServerSideProps = async function getServerSideProps(context: GetServer
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Login.isThemeSupported = false;
|
||||||
|
|
||||||
export const getServerSideProps = withNonce(_getServerSideProps);
|
export const getServerSideProps = withNonce(_getServerSideProps);
|
||||||
@@ -16,7 +16,7 @@ import { ssrInit } from "@server/lib/ssr";
|
|||||||
|
|
||||||
type Props = inferSSRProps<typeof getServerSideProps>;
|
type Props = inferSSRProps<typeof getServerSideProps>;
|
||||||
|
|
||||||
export default function Logout(props: Props) {
|
export function Logout(props: Props) {
|
||||||
const { status } = useSession();
|
const { status } = useSession();
|
||||||
if (status === "authenticated") signOut({ redirect: false });
|
if (status === "authenticated") signOut({ redirect: false });
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -31,15 +31,15 @@ export default function Logout(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")} showLogo>
|
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")} showLogo>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
|
<div className="bg-success mx-auto flex h-12 w-12 items-center justify-center rounded-full">
|
||||||
<FiCheck className="h-6 w-6 text-green-600" />
|
<FiCheck className="h-6 w-6 text-green-600" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 text-center sm:mt-5">
|
<div className="mt-3 text-center sm:mt-5">
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
<h3 className="text-emphasis text-lg font-medium leading-6" id="modal-title">
|
||||||
{t("youve_been_logged_out")}
|
{t("youve_been_logged_out")}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-gray-500">{t("hope_to_see_you_soon")}</p>
|
<p className="text-subtle text-sm">{t("hope_to_see_you_soon")}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,6 +50,10 @@ export default function Logout(props: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logout.isThemeSupported = false;
|
||||||
|
|
||||||
|
export default Logout;
|
||||||
|
|
||||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
// Deleting old cookie manually, remove this code after all existing cookies have expired
|
// Deleting old cookie manually, remove this code after all existing cookies have expired
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import EnterpriseLicense from "@components/setup/EnterpriseLicense";
|
|||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
export function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [value, setValue] = useState(props.isFreeLicense ? "FREE" : "EE");
|
const [value, setValue] = useState(props.isFreeLicense ? "FREE" : "EE");
|
||||||
@@ -103,7 +103,7 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
|||||||
id={`wizard-step-${currentStep}`}
|
id={`wizard-step-${currentStep}`}
|
||||||
name={`wizard-step-${currentStep}`}
|
name={`wizard-step-${currentStep}`}
|
||||||
classNames={{
|
classNames={{
|
||||||
form: "mb-4 rounded-md bg-white px-0 pt-0 md:max-w-full",
|
form: "mb-4 rounded-md bg-default px-0 pt-0 md:max-w-full",
|
||||||
appCategoryNavigationContainer: "max-h-[400px] overflow-y-auto md:p-4",
|
appCategoryNavigationContainer: "max-h-[400px] overflow-y-auto md:p-4",
|
||||||
verticalTabsItem: "!w-48 md:p-4",
|
verticalTabsItem: "!w-48 md:p-4",
|
||||||
}}
|
}}
|
||||||
@@ -121,7 +121,7 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Meta title={t("setup")} description={t("setup_description")} />
|
<Meta title={t("setup")} description={t("setup_description")} />
|
||||||
<main className="flex items-center bg-gray-100 print:h-full md:h-screen">
|
<main className="bg-subtle flex items-center print:h-full md:h-screen">
|
||||||
<WizardForm
|
<WizardForm
|
||||||
href="/auth/setup"
|
href="/auth/setup"
|
||||||
steps={steps}
|
steps={steps}
|
||||||
@@ -135,6 +135,10 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Setup.isThemeSupported = false;
|
||||||
|
|
||||||
|
export default Setup;
|
||||||
|
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const { req, res } = context;
|
const { req, res } = context;
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default function Verify() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-black bg-opacity-90 text-white backdrop-blur-md backdrop-grayscale backdrop-filter">
|
<div className="text-inverted bg-black bg-opacity-90 backdrop-blur-md backdrop-grayscale backdrop-filter">
|
||||||
<Head>
|
<Head>
|
||||||
<title>
|
<title>
|
||||||
{/* @note: Ternary can look ugly ant his might be extracted later but I think at 3 it's not yet worth
|
{/* @note: Ternary can look ugly ant his might be extracted later but I think at 3 it's not yet worth
|
||||||
@@ -117,11 +117,11 @@ export default function Verify() {
|
|||||||
<div className="m-10 flex max-w-2xl flex-col items-start border border-white p-12 text-left">
|
<div className="m-10 flex max-w-2xl flex-col items-start border border-white p-12 text-left">
|
||||||
<div className="rounded-full border border-white p-3">
|
<div className="rounded-full border border-white p-3">
|
||||||
{hasPaymentFailed ? (
|
{hasPaymentFailed ? (
|
||||||
<ExclamationIcon className="h-12 w-12 flex-shrink-0 p-0.5 font-extralight text-white" />
|
<ExclamationIcon className="text-inverted h-12 w-12 flex-shrink-0 p-0.5 font-extralight" />
|
||||||
) : sessionId ? (
|
) : sessionId ? (
|
||||||
<CheckIcon className="h-12 w-12 flex-shrink-0 p-0.5 font-extralight text-white" />
|
<CheckIcon className="text-inverted h-12 w-12 flex-shrink-0 p-0.5 font-extralight" />
|
||||||
) : (
|
) : (
|
||||||
<MailOpenIcon className="h-12 w-12 flex-shrink-0 p-0.5 font-extralight text-white" />
|
<MailOpenIcon className="text-inverted h-12 w-12 flex-shrink-0 p-0.5 font-extralight" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-cal my-6 text-3xl font-normal">
|
<h3 className="font-cal my-6 text-3xl font-normal">
|
||||||
@@ -139,7 +139,7 @@ export default function Verify() {
|
|||||||
{hasPaymentFailed &&
|
{hasPaymentFailed &&
|
||||||
"Once you activate your account you will be able to try purchase your premium username again or select a different one."}
|
"Once you activate your account you will be able to try purchase your premium username again or select a different one."}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-6 text-gray-400">
|
<p className="text-muted mt-6">
|
||||||
Don't see an email? Click the button below to send another email.
|
Don't see an email? Click the button below to send another email.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const DateOverride = ({ workingHours }: { workingHours: WorkingHours[] }) => {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<h3 className="font-medium leading-6 text-gray-900">
|
<h3 className="text-emphasis font-medium leading-6">
|
||||||
{t("date_overrides")}{" "}
|
{t("date_overrides")}{" "}
|
||||||
<Tooltip content={t("date_overrides_info")}>
|
<Tooltip content={t("date_overrides_info")}>
|
||||||
<span className="inline-block">
|
<span className="inline-block">
|
||||||
@@ -61,7 +61,7 @@ const DateOverride = ({ workingHours }: { workingHours: WorkingHours[] }) => {
|
|||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mb-4 text-sm text-gray-500">{t("date_overrides_subtitle")}</p>
|
<p className="text-subtle mb-4 text-sm">{t("date_overrides_subtitle")}</p>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<DateOverrideList
|
<DateOverrideList
|
||||||
excludedDates={fields.map((field) => yyyymmdd(field.ranges[0].start))}
|
excludedDates={fields.map((field) => yyyymmdd(field.ranges[0].start))}
|
||||||
@@ -181,7 +181,7 @@ export default function Availability() {
|
|||||||
}
|
}
|
||||||
CTA={
|
CTA={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
|
<div className="sm:hover:bg-subtle flex items-center rounded-md px-2">
|
||||||
<Skeleton
|
<Skeleton
|
||||||
as={Label}
|
as={Label}
|
||||||
htmlFor="hiddenSwitch"
|
htmlFor="hiddenSwitch"
|
||||||
@@ -225,7 +225,7 @@ export default function Availability() {
|
|||||||
|
|
||||||
<VerticalDivider />
|
<VerticalDivider />
|
||||||
|
|
||||||
<div className="border-l-2 border-gray-300" />
|
<div className="border-default border-l-2" />
|
||||||
<Button className="ml-4 lg:ml-0" type="submit" form="availability-form">
|
<Button className="ml-4 lg:ml-0" type="submit" form="availability-form">
|
||||||
{t("save")}
|
{t("save")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -245,7 +245,7 @@ export default function Availability() {
|
|||||||
}}
|
}}
|
||||||
className="flex flex-col sm:mx-0 xl:flex-row xl:space-x-6">
|
className="flex flex-col sm:mx-0 xl:flex-row xl:space-x-6">
|
||||||
<div className="flex-1 flex-row xl:mr-0">
|
<div className="flex-1 flex-row xl:mr-0">
|
||||||
<div className="mb-6 rounded-md border">
|
<div className="border-subtle mb-6 rounded-md border">
|
||||||
<div>
|
<div>
|
||||||
{typeof me.data?.weekStart === "string" && (
|
{typeof me.data?.weekStart === "string" && (
|
||||||
<Schedule
|
<Schedule
|
||||||
@@ -260,14 +260,14 @@ export default function Availability() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-6 rounded-md border">
|
<div className="border-subtle my-6 rounded-md border">
|
||||||
{schedule?.workingHours && <DateOverride workingHours={schedule.workingHours} />}
|
{schedule?.workingHours && <DateOverride workingHours={schedule.workingHours} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
||||||
<div className="xl:max-w-80 w-full pr-4 sm:ml-0 sm:mr-36 sm:p-0">
|
<div className="xl:max-w-80 w-full pr-4 sm:ml-0 sm:mr-36 sm:p-0">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="timeZone" className="text-default block text-sm font-medium">
|
||||||
{t("timezone")}
|
{t("timezone")}
|
||||||
</label>
|
</label>
|
||||||
<Controller
|
<Controller
|
||||||
@@ -276,7 +276,7 @@ export default function Availability() {
|
|||||||
value ? (
|
value ? (
|
||||||
<TimezoneSelect
|
<TimezoneSelect
|
||||||
value={value}
|
value={value}
|
||||||
className="focus:border-brand mt-1 block w-72 rounded-md border-gray-300 text-sm"
|
className="focus:border-brand-default border-default mt-1 block w-72 rounded-md text-sm"
|
||||||
onChange={(timezone) => onChange(timezone.value)}
|
onChange={(timezone) => onChange(timezone.value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -285,9 +285,9 @@ export default function Availability() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<hr className="my-6 mr-8" />
|
<hr className="border-subtle my-6 mr-8" />
|
||||||
<div className="hidden rounded-md md:block">
|
<div className="hidden rounded-md md:block">
|
||||||
<h3 className="text-sm font-medium text-gray-900">{t("something_doesnt_look_right")}</h3>
|
<h3 className="text-emphasis text-sm font-medium">{t("something_doesnt_look_right")}</h3>
|
||||||
<div className="mt-3 flex">
|
<div className="mt-3 flex">
|
||||||
<Button href="/availability/troubleshoot" color="secondary">
|
<Button href="/availability/troubleshoot" color="secondary">
|
||||||
{t("launch_troubleshooter")}
|
{t("launch_troubleshooter")}
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mb-16 overflow-hidden rounded-md border border-gray-200 bg-white">
|
<div className="border-subtle bg-default mb-16 overflow-hidden rounded-md border">
|
||||||
<ul className="divide-y divide-gray-200" data-testid="schedules" ref={animationParentRef}>
|
<ul className="divide-subtle divide-y" data-testid="schedules" ref={animationParentRef}>
|
||||||
{schedules.map((schedule) => (
|
{schedules.map((schedule) => (
|
||||||
<ScheduleListItem
|
<ScheduleListItem
|
||||||
displayOptions={{
|
displayOptions={{
|
||||||
@@ -92,14 +92,9 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
|
|||||||
}}
|
}}
|
||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
|
isDeletable={schedules.length !== 1}
|
||||||
updateDefault={updateMutation.mutate}
|
updateDefault={updateMutation.mutate}
|
||||||
deleteFunction={() => {
|
deleteFunction={deleteMutation.mutate}
|
||||||
if (schedules.length === 1) {
|
|
||||||
showToast(t("requires_at_least_one_schedule"), "error");
|
|
||||||
} else {
|
|
||||||
deleteMutation.mutate;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||||||
}, [] as IBusySlot[]) || [];
|
}, [] as IBusySlot[]) || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-xl overflow-hidden rounded-md bg-white shadow">
|
<div className="bg-default max-w-xl overflow-hidden rounded-md shadow">
|
||||||
<div className="px-4 py-5 sm:p-6">
|
<div className="px-4 py-5 sm:p-6">
|
||||||
{t("overview_of_day")}{" "}
|
{t("overview_of_day")}{" "}
|
||||||
<input
|
<input
|
||||||
@@ -57,7 +57,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||||||
if (e.target.value) setSelectedDate(e.target.value);
|
if (e.target.value) setSelectedDate(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<small className="block text-gray-400">{t("hover_over_bold_times_tip")}</small>
|
<small className="text-muted block">{t("hover_over_bold_times_tip")}</small>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
<div className="bg-brand dark:bg-darkmodebrand overflow-hidden rounded-md">
|
<div className="bg-brand dark:bg-darkmodebrand overflow-hidden rounded-md">
|
||||||
<div className="text-brandcontrast dark:text-darkmodebrandcontrast px-4 py-2 sm:px-6">
|
<div className="text-brandcontrast dark:text-darkmodebrandcontrast px-4 py-2 sm:px-6">
|
||||||
@@ -79,15 +79,15 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||||||
.map((slot: IBusySlot) => (
|
.map((slot: IBusySlot) => (
|
||||||
<div
|
<div
|
||||||
key={dayjs(slot.start).format("HH:mm")}
|
key={dayjs(slot.start).format("HH:mm")}
|
||||||
className="overflow-hidden rounded-md bg-gray-100"
|
className="bg-subtle overflow-hidden rounded-md"
|
||||||
data-testid="troubleshooter-busy-time">
|
data-testid="troubleshooter-busy-time">
|
||||||
<div className="px-4 py-5 text-black sm:p-6">
|
<div className="text-emphasis px-4 py-5 sm:p-6">
|
||||||
{t("calendar_shows_busy_between")}{" "}
|
{t("calendar_shows_busy_between")}{" "}
|
||||||
<span className="font-medium text-gray-800" title={dayjs(slot.start).format("HH:mm")}>
|
<span className="text-default font-medium" title={dayjs(slot.start).format("HH:mm")}>
|
||||||
{dayjs(slot.start).format("HH:mm")}
|
{dayjs(slot.start).format("HH:mm")}
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{t("and")}{" "}
|
{t("and")}{" "}
|
||||||
<span className="font-medium text-gray-800" title={dayjs(slot.end).format("HH:mm")}>
|
<span className="text-default font-medium" title={dayjs(slot.end).format("HH:mm")}>
|
||||||
{dayjs(slot.end).format("HH:mm")}
|
{dayjs(slot.end).format("HH:mm")}
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{t("on")} {dayjs(slot.start).format("D")}{" "}
|
{t("on")} {dayjs(slot.start).format("D")}{" "}
|
||||||
@@ -98,8 +98,8 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden rounded-md bg-gray-100">
|
<div className="bg-subtle overflow-hidden rounded-md">
|
||||||
<div className="px-4 py-5 text-black sm:p-6">{t("calendar_no_busy_slots")}</div>
|
<div className="text-emphasis px-4 py-5 sm:p-6">{t("calendar_no_busy_slots")}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
Loaded 100 of 491 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user