Compare commits

...
75 Commits
Author SHA1 Message Date
9441da9d4e fix: custom meeting link overflowing (#9804)
release.yml / release (push) Canceled after 0s
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-06-26 19:35:55 +00:00
Pradumn Kumar 1510740cb2 fix: adds triggerEvent attribute to meeting ended webhook (#9806) 2023-06-26 14:35:32 -04:00
Keith Williams 8da68cc1fe chore: Added test SendGrid env variables (#9807) 2023-06-26 18:59:39 +02:00
Crowdin Bot 6dbc8dd820 New Crowdin translations by Github Action 2023-06-26 15:25:09 +00:00
Hariom Balhara 4ada428bcb fix: Embed - Better support for layout config(without flash of default toggle) (#9714) 2023-06-26 17:24:19 +02:00
Crowdin Bot 6adaf0d3e8 New Crowdin translations by Github Action 2023-06-26 14:11:17 +00:00
Peer Richelsen c9e6acfa69 Update common.json (#9788) 2023-06-26 19:40:13 +05:30
Hariom Balhara 2272da5ee7 test: New Booker Tests for Embed (#9666) 2023-06-26 15:27:24 +02:00
Carina WollendorferandCarinaWolli 79b3875af3 fix: add UAE to list of non alphanumeric sender id support (#9752)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-06-26 15:25:27 +02:00
Peer Richelsen d16b6fce8f Update package.json 2023-06-26 15:13:31 +02:00
Gaurav Goswami 40b35bdbe4 bug/changed icon (#9801) 2023-06-26 13:00:19 +00:00
Keith Williams 0af76ec5ab chore: Updated staleness check to start with old content (#9800) 2023-06-26 14:49:41 +02:00
Ayush Mainali f7b20da640 fix: fixed layout shift issue of top banner (#9791) 2023-06-26 14:12:57 +02:00
Ritik KumarandCarina Wollendorfer eedf6913b8 feat: allow duplicate availability (#9615)
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2023-06-26 07:35:20 -04:00
78393a2b8b feat: disable workflows and webhooks for orgs + UI changes [CAL-1873] (#9504)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
2023-06-26 06:37:59 -04:00
Kinjalk Bajpai b3d64104b0 fix: Removing 2fa text that appears twice (#9762) 2023-06-25 15:21:39 +00:00
9266ba1e48 fix: don't show tool-tip when negative or zero recurring events (#9612)
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-25 15:09:32 +00:00
Ujwal Kumar ec212e4317 fix-borders-on-weekly-view (#9770) 2023-06-25 17:04:25 +02:00
Kinjalk Bajpai 02d4f0542a fix: Broken Heroku Image in README.md (#9772) 2023-06-25 16:59:36 +02:00
Crowdin Bot 0aae07ae2f New Crowdin translations by Github Action 2023-06-23 20:50:05 +00:00
Daniel Roe 80ab6c9c98 fix: add space to make link clickable (#9763) 2023-06-23 22:49:20 +02:00
Afzal Sayed 86ba0766fc Prevent invalid api call (#9757) 2023-06-23 22:48:38 +02:00
Crowdin Bot 0adde17f38 New Crowdin translations by Github Action 2023-06-23 20:03:43 +00:00
Crowdin Bot 9e4700f9df New Crowdin translations by Github Action 2023-06-23 20:02:48 +00:00
Leo Giovanetti f4a87c66b3 Adding team and org registration suggestion (#9764) 2023-06-23 22:01:54 +02:00
0c06f1f6cb feat: Add google spam warning on booking confirmation page for gmail users ( CALCOM-9247) (#9531)
* feat: Add google spam warning on booking confirmation page for gmail users

* Update apps/web/pages/booking/[uid].tsx

Co-authored-by: alannnc <alannnc@gmail.com>

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-06-23 17:13:16 +00:00
Hariom Balhara b731dfd421 fix: Error during booking when default app is a Static Link Video App and Event has Organizer default location selected. (#9734) 2023-06-23 19:04:34 +02:00
sean-brydon 0b704b9ed4 test: Remove mockdate and replate with vitest system time (#9750) 2023-06-23 16:10:43 +00:00
Soham DattaandBailey Pumfleet a0ece0d77e fix: added loading skeleton for teams profile view (#9746)
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-06-23 13:14:18 +00:00
Crowdin Bot 7839381911 New Crowdin translations by Github Action 2023-06-23 12:52:50 +00:00
Hariom Balhara 6a976f5b42 feat: New Booker: Disable dialog form in mobile in embed (#9748) 2023-06-23 18:22:03 +05:30
Peer Richelsenandalannnc 8718905474 docs: added "commerical" to API readme (#9636)
* Update README.md

* Update apps/api/README.md

* Update apps/api/README.md

---------

Co-authored-by: alannnc <alannnc@gmail.com>
2023-06-23 11:06:01 +02:00
Jaideep Guntupalli ff968d3867 fix: Added relevant colors to preset and replaced with tailwind colors (#9733) 2023-06-23 09:05:37 +00:00
Jaideep Guntupalliandsean-brydon 8f5e6370b0 feat: Added Storybook Controls (#9676)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-06-23 09:04:26 +00:00
Peer Richelsen 0a0c400333 Update package.json
release.yml / release (push) Canceled after 0s
2023-06-23 10:58:34 +02:00
Anit Jha 0eb05aa540 fix: Public Link of pending members is now disabled (#9730) 2023-06-23 10:53:00 +02:00
Crowdin Bot efe18ebdcd New Crowdin translations by Github Action 2023-06-23 08:51:18 +00:00
Crowdin Bot ce097b89ba New Crowdin translations by Github Action 2023-06-23 08:50:29 +00:00
Deepak Rudra PaulandDeepak Paul bb0e6389fa fix: Fixed delete event-type button (#9739)
Co-authored-by: Deepak Paul <rudra.ad7@gmail.com>
2023-06-23 10:49:53 +02:00
Nafees Nazik 19a7cd1a50 fix: invite modal (#9713)
* fix: invite modal

* fix: truncate text
2023-06-23 10:48:20 +02:00
Hariom Balhara 49bcd5fec7 Event Analytics not working for new booker (#9740) 2023-06-23 08:42:02 +00:00
Udit Takkar 000a6e0d35 fix: location details on new booker (#9710)
* fix: location details on new booker

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* chore

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-06-23 11:53:00 +05:30
Alex van Andel 52936f60b4 fix: Various errors & 500 error on duplicate url when editing (#9731) 2023-06-23 07:03:45 +02:00
Omar López 2d6eebcd8a chore: Sync packages mismatches (#9725) 2023-06-22 15:25:37 -07:00
Keith Williamsandalannnc cfa6a5b996 chore: Added unit tests for converting availability to string (#9617)
* Added unit tests for availability to string

* Testing to see if extra toString() removes unicode

* Replacing unicode space

* Updated to regex

* Reverted files that were not supposed to change

* Reverted schema changes

* Added comment

* Type check

* Change function call structure

---------

Co-authored-by: alannnc <alannnc@gmail.com>
2023-06-22 22:19:50 +00:00
sean-brydon 7413ba6aa0 Fixes overflow + zindex of cal icon (#9707) 2023-06-22 19:46:42 +00:00
Deepak Rudra PaulandDeepak Paul e9cbe5d353 fix:copy-invite-link button (#9721)
Co-authored-by: Deepak Paul <rudra.ad7@gmail.com>
2023-06-22 21:35:09 +02:00
Alex van Andel d8bc9acbbc feat: remove member from hosts on removal (#9722)
* feat: When a member is removed we should remove it from the hosts

* Add migration for fixing old records affected
2023-06-22 21:33:03 +02:00
Hariom Balhara 4f0e843ac6 test: Make embed tests stable. (#9718)
* Wait for /embed/embed.js to be servable

* Change something in embeds/ to make embed tests run
2023-06-22 17:38:51 +02:00
sean-brydon 02f1c50bb2 Fix settings layout + org headings (#9712) 2023-06-22 11:57:00 +01:00
GitStart-Cal.comandgitstart-calcom 5952a38ab9 feat: [CAL-910] Pre-select country for phone number (CALCOM-5759) (#9526)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-06-22 10:18:05 +02:00
Efraín Rochín e5fb19163e perf: Remove useless data on EvenTypes getByViewer endpoint (#9704) 2023-06-22 10:16:53 +02:00
79f34a4fc7 perf: [CAL-1928] Deduplicate eventTypes.getByViewer query (#9700)
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2023-06-22 10:16:34 +02:00
Crowdin Bot 3e90c08d55 New Crowdin translations by Github Action 2023-06-22 07:34:42 +00:00
Hariom Balhara 697d8eca43 Allow closing the embed on clicking the black transparent area (#9706) 2023-06-22 07:33:50 +00:00
Omar López 5cecf3104f refactor: Skip license checks for development (#9375) 2023-06-21 23:13:26 -03:00
Crowdin Bot a3a6caa6dd New Crowdin translations by Github Action 2023-06-21 23:30:55 +00:00
Omar López d3586c9039 Revert "fix: redirect to 404 page for invalid email verification token" (#9703) 2023-06-21 23:29:53 +00:00
71eafa287a feat: Organizations no middleware rewrite (#9548)
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-21 21:12:12 +00:00
Keith Williams 828ef8580e v3.0.5
release.yml / release (push) Canceled after 0s
2023-06-21 18:39:37 +02:00
Jeroen Reumkens a348c3a20a CAL-1892: Show booker layout dark mode preview based on theme the user selects (#9664) 2023-06-21 17:14:23 +02:00
Omar López 3c68c7f7cb chore: Upgrades prisma to 4.16 (#9670)
* Upgrades prisma to 4.16

* typefix
2023-06-21 17:07:54 +02:00
Hariom Balhara 820b2da16d test: Add RegExp tests for Next.config.js rewrites (#9681)
* Add RegExp tests

* Update apps/web/test/lib/next-config.test.ts

* Dont avoid rewrite for /booked event slug

* Add /embed/embed.js test

* Add dynamic group booking link test
2023-06-21 17:06:44 +02:00
sean-brydon 6bdb2b94eb feat: Adds sheet component (#9680)
* Adds sheet component

* Fix overlay

* Calc math
2023-06-21 15:29:23 +01:00
Hariom Balhara 3c3db0b3a6 fix: Hotfix/ Dynamic Group Booking Links not working in new booker (#9685)
* Debuglogs

* Derive group usernames correctly

* Revert "Debuglogs"

This reverts commit d93f031589b34bb7fee32a34f96eb89805c20275.
2023-06-21 15:22:13 +01:00
Hariom Balhara 4748641c22 fix: Hotfix/main - 404 workflows (#9678) 2023-06-21 15:39:03 +05:30
Jeroen Reumkens 804787f2a3 Get brand colors from DB for owner, so it's reflected in booker (#9679) 2023-06-21 09:04:15 +00:00
Alex van Andel b7c3b31e0c fix: eventType-getByViewer subselect on children->users[] (#9668) 2023-06-21 08:56:42 +00:00
Jeroen ReumkensandHariom Balhara ab6781cd72 fix: Booker fix for team + user with same event + event slug (#9654)
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-06-21 13:01:55 +05:30
Crowdin Bot b070cfb227 New Crowdin translations by Github Action 2023-06-21 07:29:17 +00:00
Hariom Balhara 5acb3a09e5 fix: Hide EventTypeDetails when configured (#9633) 2023-06-21 12:58:21 +05:30
Crowdin Bot 69c9f690cb New Crowdin translations by Github Action 2023-06-20 17:55:04 +00:00
Ayush Mainali d2a12ea834 refactor: Convert card to cva (#9651) 2023-06-20 19:54:08 +02:00
16f24b4831 feat: [CAL-1435] Emptyscreen for App Store if no external app has been configured (CALCOM-8154) (#9516)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-20 19:53:33 +02:00
sean-brydon a3eeeab259 feat: Handle deleting vercel domain when org is deleted (#9661) 2023-06-20 17:57:21 +02:00
306 changed files with 3535 additions and 1897 deletions

No files matched your search

+2
View File
@@ -26,11 +26,13 @@ Fixes # (issue)
- [ ] Test B - [ ] Test B
## Mandatory Tasks ## Mandatory Tasks
- [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected. - [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected.
## Checklist ## Checklist
<!-- Please remove all the irrelevant bullets to your PR --> <!-- Please remove all the irrelevant bullets to your PR -->
- I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code doesn't follow the style guidelines of this project - My code doesn't follow the style guidelines of this project
- I haven't commented my code, particularly in hard-to-understand areas - I haven't commented my code, particularly in hard-to-understand areas
+1
View File
@@ -16,6 +16,7 @@ jobs:
steps: steps:
- uses: actions/stale@v7 - uses: actions/stale@v7
with: with:
ascending: true
days-before-issue-stale: 60 days-before-issue-stale: 60
days-before-issue-close: -1 days-before-issue-close: -1
days-before-pr-stale: 14 days-before-pr-stale: 14
+2
View File
@@ -31,6 +31,8 @@ env:
# INPUT_ENV_MS_GRAPH_CLIENT_SECRET: xxx # INPUT_ENV_MS_GRAPH_CLIENT_SECRET: xxx
# INPUT_ENV_ZOOM_CLIENT_ID: xxx # INPUT_ENV_ZOOM_CLIENT_ID: xxx
# INPUT_ENV_ZOOM_CLIENT_SECRET: xxx # INPUT_ENV_ZOOM_CLIENT_SECRET: xxx
INPUT_ENV_SENDGRID_API_KEY: ${{ secrets.CI_SENDGRID_API_KEY }}
INPUT_ENV_SENDGRID_EMAIL: ${{ secrets.CI_SENDGRID_EMAIL }}
INPUT_ENV_TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} INPUT_ENV_TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
INPUT_ENV_TURBO_TEAM: ${{ secrets.TURBO_TEAM }} INPUT_ENV_TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
+3
View File
@@ -34,12 +34,15 @@ jobs:
app-store: app-store:
- 'apps/web/**' - 'apps/web/**'
- 'packages/app-store/**' - 'packages/app-store/**'
- 'playwright.config.ts'
embed: embed:
- 'apps/web/**' - 'apps/web/**'
- 'packages/embeds/**' - 'packages/embeds/**'
- 'playwright.config.ts'
embed-react: embed-react:
- 'apps/web/**' - 'apps/web/**'
- 'packages/embeds/**' - 'packages/embeds/**'
- 'playwright.config.ts'
env: env:
name: Create env file name: Create env file
+15 -11
View File
@@ -121,9 +121,9 @@ Here is what you need to be able to run Cal.com.
```sh ```sh
git clone https://github.com/calcom/cal.com.git git clone https://github.com/calcom/cal.com.git
``` ```
> If you are on windows, run the following command on `gitbash` with admin privileges: <br>
```git clone -c core.symlinks=true https://github.com/calcom/cal.com.git``` <br> > If you are on windows, run the following command on `gitbash` with admin privileges: <br> > `git clone -c core.symlinks=true https://github.com/calcom/cal.com.git` <br>
See [docs](https://cal.com/docs/how-to-guides/how-to-troubleshoot-symbolic-link-issues-on-windows#enable-symbolic-links) for more details. > See [docs](https://cal.com/docs/how-to-guides/how-to-troubleshoot-symbolic-link-issues-on-windows#enable-symbolic-links) for more details.
1. Go to the project folder 1. Go to the project folder
@@ -158,6 +158,7 @@ yarn dx
```sh ```sh
echo 'NEXT_PUBLIC_DEBUG=1' >> .env echo 'NEXT_PUBLIC_DEBUG=1' >> .env
``` ```
#### Gitpod Setup #### Gitpod Setup
1. Click the button below to open this project in Gitpod. 1. Click the button below to open this project in Gitpod.
@@ -166,8 +167,6 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> .env
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/calcom/cal.com) [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/calcom/cal.com)
#### Manual setup #### Manual setup
1. Configure environment variables in the `.env` file. Replace `<user>`, `<pass>`, `<db-host>`, and `<db-port>` with their applicable values 1. Configure environment variables in the `.env` file. Replace `<user>`, `<pass>`, `<db-host>`, and `<db-port>` with their applicable values
@@ -175,24 +174,26 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> .env
``` ```
DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>' DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>'
``` ```
<details> <details>
<summary>If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick local DB</summary> <summary>If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick local DB</summary>
1. [Download](https://www.postgresql.org/download/) and install postgres in your local (if you don't have it already). 1. [Download](https://www.postgresql.org/download/) and install postgres in your local (if you don't have it already).
2. Create your own local db by executing `createDB <DB name>` 2. Create your own local db by executing `createDB <DB name>`
3. Now open your psql shell with the DB you created: `psql -h localhost -U postgres -d <DB name>` 3. Now open your psql shell with the DB you created: `psql -h localhost -U postgres -d <DB name>`
4. Inside the psql shell execute `\conninfo`. And you will get the following info. 4. Inside the psql shell execute `\conninfo`. And you will get the following info.
![image](https://user-images.githubusercontent.com/39329182/236612291-51d87f69-6dc1-4a23-bf4d-1ca1754e0a35.png) ![image](https://user-images.githubusercontent.com/39329182/236612291-51d87f69-6dc1-4a23-bf4d-1ca1754e0a35.png)
5. Now extract all the info and add it to your DATABASE_URL. The url would look something like this 5. Now extract all the info and add it to your DATABASE_URL. The url would look something like this
`postgresql://postgres:postgres@localhost:5432/Your-DB-Name`. `postgresql://postgres:postgres@localhost:5432/Your-DB-Name`.
</details> </details>
If you don't want to create a local DB. Then you can also consider using services like railway.app or render. If you don't want to create a local DB. Then you can also consider using services like railway.app or render.
- [Setup postgres DB with railway.app](https://arctype.com/postgres/setup/railway-postgres) - [Setup postgres DB with railway.app](https://arctype.com/postgres/setup/railway-postgres)
- [Setup postgres DB with render](https://render.com/docs/databases) - [Setup postgres DB with render](https://render.com/docs/databases)
@@ -208,10 +209,11 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> .env
``` ```
In a production environment, run: In a production environment, run:
```sh ```sh
yarn workspace @calcom/prisma db-deploy yarn workspace @calcom/prisma db-deploy
``` ```
1. Run [mailhog](https://github.com/mailhog/MailHog) to view emails sent during development 1. Run [mailhog](https://github.com/mailhog/MailHog) to view emails sent during development
```sh ```sh
@@ -319,7 +321,7 @@ Cal.com, Inc. does not provide official support for Docker, but we will accept f
### Heroku ### Heroku
<a href="https://heroku.com/deploy?template=https://github.com/calcom/cal.com"> <a href="https://heroku.com/deploy?template=https://github.com/calcom/cal.com">
<img width="185px" height="auto" src="https://herokucdn.com/deploy/button.svg" alt="Deploy"> <img width="185px" height="auto" src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
</a> </a>
### Railway ### Railway
@@ -490,7 +492,9 @@ following
10. You're good to go. Now you can easily add your ZohoCRM integration in the Cal.com settings. 10. You're good to go. Now you can easily add your ZohoCRM integration in the Cal.com settings.
### Obtaining Zoho Bigin Client ID and Secret ### Obtaining Zoho Bigin Client ID and Secret
[Follow these steps](./packages/app-store/zoho-bigin/) [Follow these steps](./packages/app-store/zoho-bigin/)
## Workflows ## Workflows
### Setting up SendGrid for Email reminders ### Setting up SendGrid for Email reminders
+1 -1
View File
@@ -7,7 +7,7 @@
<a href="https://cal.com/docs/enterprise-features/api#api-server-specifications">Read the API docs</a> <a href="https://cal.com/docs/enterprise-features/api#api-server-specifications">Read the API docs</a>
</div> </div>
# Cal.com Public API # Commercial Cal.com Public API
Welcome to the Public API ("/apps/api") of the Cal.com. Welcome to the Public API ("/apps/api") of the Cal.com.
+2 -2
View File
@@ -32,9 +32,9 @@
"@sentry/nextjs": "^7.20.0", "@sentry/nextjs": "^7.20.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"next": "~13.4.6", "next": "^13.4.6",
"next-api-middleware": "^1.0.1", "next-api-middleware": "^1.0.1",
"next-axiom": "^0.16.0", "next-axiom": "^0.17.0",
"next-swagger-doc": "^0.3.6", "next-swagger-doc": "^0.3.6",
"next-validations": "^0.2.0", "next-validations": "^0.2.0",
"typescript": "^4.9.4", "typescript": "^4.9.4",
@@ -2,7 +2,7 @@ import { CAL_URL } from "@calcom/lib/constants";
export default function getCalLink(eventType: { export default function getCalLink(eventType: {
team?: { slug: string | null } | null; team?: { slug: string | null } | null;
owner: { username: string | null } | null; owner?: { username: string | null } | null;
users?: { username: string | null }[]; users?: { username: string | null }[];
slug: string; slug: string;
}) { }) {
+5 -5
View File
@@ -26,15 +26,15 @@ export function VariantsTable({
<table> <table>
<RowTitles titles={titles} /> <RowTitles titles={titles} />
{columns.map((column) => ( {columns.map((column) => (
<tr className="p-2 pr-6 pb-6" key={column.props.variant}> <tr className="p-2 pb-6 pr-6" key={column.props.variant}>
<th <th
className="p-2 pr-6 pb-6 text-left text-sm font-normal text-[#8F8F8F]" className="p-2 pb-6 pr-6 text-left text-sm font-normal text-[#8F8F8F]"
key={column.props.variant}> key={column.props.variant}>
{column.props.variant} {column.props.variant}
</th> </th>
{React.Children.count(column.props.children) && {React.Children.count(column.props.children) &&
React.Children.map(column.props.children, (cell) => ( React.Children.map(column.props.children, (cell) => (
<td className="p-2 pr-6 pb-6" style={{ minWidth: `${columnMinWidth}px` }}> <td className="p-2 pb-6 pr-6" style={{ minWidth: `${columnMinWidth}px` }}>
{cell} {cell}
</td> </td>
))} ))}
@@ -70,9 +70,9 @@ export function VariantRow({ children }: RowProps) {
export function RowTitles({ titles }: { titles: string[] }) { export function RowTitles({ titles }: { titles: string[] }) {
return ( return (
<tr> <tr>
<th className="p-2 pr-6 pb-6 text-left text-sm font-normal text-[#8F8F8F]" /> <th className="p-2 pb-6 pr-6 text-left text-sm font-normal text-[#8F8F8F]" />
{titles.map((title) => ( {titles.map((title) => (
<th className="p-2 pr-6 pb-6 text-left text-sm font-normal text-[#8F8F8F]" key={title}> <th className="p-2 pb-6 pr-6 text-left text-sm font-normal text-[#8F8F8F]" key={title}>
{title} {title}
</th> </th>
))} ))}
+4 -4
View File
@@ -13,7 +13,7 @@
"@radix-ui/react-avatar": "^1.0.0", "@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-collapsible": "^1.0.0", "@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0", "@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0", "@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-id": "^1.0.0", "@radix-ui/react-id": "^1.0.0",
"@radix-ui/react-popover": "^1.0.2", "@radix-ui/react-popover": "^1.0.2",
"@radix-ui/react-radio-group": "^1.0.0", "@radix-ui/react-radio-group": "^1.0.0",
@@ -37,8 +37,8 @@
"@storybook/react": "^6.5.13", "@storybook/react": "^6.5.13",
"@storybook/testing-library": "^0.0.13", "@storybook/testing-library": "^0.0.13",
"@types/react": "18.0.26", "@types/react": "18.0.26",
"@types/react-dom": "18.0.9", "@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^2.1.0", "@vitejs/plugin-react": "^2.2.0",
"autoprefixer": "^10.4.12", "autoprefixer": "^10.4.12",
"babel-loader": "^8.2.5", "babel-loader": "^8.2.5",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
@@ -48,7 +48,7 @@
"storybook-addon-designs": "^6.3.1", "storybook-addon-designs": "^6.3.1",
"storybook-addon-next": "^1.6.9", "storybook-addon-next": "^1.6.9",
"storybook-react-i18next": "^1.1.2", "storybook-react-i18next": "^1.1.2",
"tailwindcss": "^3.2.1", "tailwindcss": "^3.3.1",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"vite": "^4.1.2" "vite": "^4.1.2"
} }
@@ -209,6 +209,7 @@
--cal-bg-success: #E2FBE8; --cal-bg-success: #E2FBE8;
--cal-bg-attention: #FCEED8; --cal-bg-attention: #FCEED8;
--cal-bg-error: #F9E3E2; --cal-bg-error: #F9E3E2;
--cal-bg-dark-error: #752522;
/* Borders */ /* Borders */
@@ -216,6 +217,7 @@
--cal-border: #D1D5DB; --cal-border: #D1D5DB;
--cal-border-subtle:#E5E7EB; --cal-border-subtle:#E5E7EB;
--cal-border-muted:#F3F4F6; --cal-border-muted:#F3F4F6;
--cal-border-error: #aa2e26;
/* Content/Text */ /* Content/Text */
--cal-text-emphasis: #111827; --cal-text-emphasis: #111827;
@@ -251,6 +253,7 @@
--cal-bg-success: #E2FBE8; --cal-bg-success: #E2FBE8;
--cal-bg-attention: #FCEED8; --cal-bg-attention: #FCEED8;
--cal-bg-error: #F9E3E2; --cal-bg-error: #F9E3E2;
--cal-bg-dark-error: #752522;
/* Borders */ /* Borders */
@@ -258,6 +261,7 @@
--cal-border: #444444; --cal-border: #444444;
--cal-border-subtle: #2B2B2B; --cal-border-subtle: #2B2B2B;
--cal-border-muted: #1C1C1C; --cal-border-muted: #1C1C1C;
--cal-border-error: #aa2e26;
/* Content/Text */ /* Content/Text */
--cal-text-emphasis: #F3F4F6; --cal-text-emphasis: #F3F4F6;
+1 -1
View File
@@ -23,7 +23,7 @@
"devDependencies": { "devDependencies": {
"@types/node": "16.9.1", "@types/node": "16.9.1",
"@types/react": "18.0.26", "@types/react": "18.0.26",
"@types/react-dom": "18.0.9", "@types/react-dom": "^18.0.9",
"typescript": "^4.9.4" "typescript": "^4.9.4"
} }
} }
+81 -19
View File
@@ -10,7 +10,7 @@ import { components } from "react-select";
import type { BookerLayout } from "@calcom/features/bookings/Booker/types"; import type { BookerLayout } from "@calcom/features/bookings/Booker/types";
import { useFlagMap } from "@calcom/features/flags/context/provider"; import { useFlagMap } from "@calcom/features/flags/context/provider";
import { APP_NAME, EMBED_LIB_URL, WEBAPP_URL } from "@calcom/lib/constants"; import { APP_NAME, EMBED_LIB_URL, IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { BookerLayouts } from "@calcom/prisma/zod-utils"; import { BookerLayouts } from "@calcom/prisma/zod-utils";
import { import {
@@ -38,13 +38,21 @@ const enum Theme {
dark = "dark", dark = "dark",
} }
const EMBED_CAL_ORIGIN = WEBAPP_URL;
const EMBED_CAL_JS_URL = `${WEBAPP_URL}/embed/embed.js`;
type PreviewState = { type PreviewState = {
inline: { inline: {
width: string; width: string;
height: string; height: string;
}; };
theme: Theme; theme: Theme;
floatingPopup: Record<string, string | boolean | undefined>; floatingPopup: {
config?: {
layout: BookerLayouts;
};
[key: string]: string | boolean | undefined | Record<string, string>;
};
elementClick: Record<string, string>; elementClick: Record<string, string>;
palette: { palette: {
brandColor: string; brandColor: string;
@@ -175,14 +183,24 @@ const Codes: Record<string, Record<string, (...args: any[]) => string>> = {
return code` return code`
import Cal, { getCalApi } from "@calcom/embed-react"; import Cal, { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react"; import { useEffect } from "react";
function MyComponent() { export default function MyApp() {
useEffect(()=>{ useEffect(()=>{
(async function () { (async function () {
const cal = await getCalApi(); const cal = await getCalApi();
${uiInstructionCode} ${uiInstructionCode}
})(); })();
}, []) }, [])
return <Cal calLink="${calLink}" style={{width:"${width}",height:"${height}",overflow:"scroll"}} />; return <Cal
calLink="${calLink}"
style={{width:"${width}",height:"${height}",overflow:"scroll"}}
${previewState.layout ? "config={{layout: '" + previewState.layout + "'}}" : ""}${
IS_SELF_HOSTED
? `
calOrigin="${EMBED_CAL_ORIGIN}"
calJsUrl="${EMBED_CAL_JS_URL}"`
: ""
}
/>;
};`; };`;
}, },
"floating-popup": ({ "floating-popup": ({
@@ -193,38 +211,60 @@ function MyComponent() {
uiInstructionCode: string; uiInstructionCode: string;
}) => { }) => {
return code` return code`
import Cal, { getCalApi } from "@calcom/embed-react"; import { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react"; import { useEffect } from "react";
function MyComponent() { export default function App() {
useEffect(()=>{ useEffect(()=>{
(async function () { (async function () {
const cal = await getCalApi(); const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
cal("floatingButton", ${floatingButtonArg}); cal("floatingButton", ${floatingButtonArg});
${uiInstructionCode} ${uiInstructionCode}
})(); })();
}, []) }, [])
};`; };`;
}, },
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => { "element-click": ({
calLink,
uiInstructionCode,
previewState,
}: {
calLink: string;
uiInstructionCode: string;
previewState: PreviewState;
}) => {
return code` return code`
import Cal, { getCalApi } from "@calcom/embed-react"; import { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react"; import { useEffect } from "react";
function MyComponent() { export default function App() {
useEffect(()=>{ useEffect(()=>{
(async function () { (async function () {
const cal = await getCalApi(); const cal = await getCalApi(${IS_SELF_HOSTED ? `"${EMBED_CAL_JS_URL}"` : ""});
${uiInstructionCode} ${uiInstructionCode}
})(); })();
}, []) }, [])
return <button data-cal-link="${calLink}" />; return <button
data-cal-link="${calLink}"${IS_SELF_HOSTED ? `\ndata-cal-origin="${EMBED_CAL_ORIGIN}"` : ""}
${`data-cal-config='${JSON.stringify({
layout: previewState.layout,
})}'`}
>Click me</button>;
};`; };`;
}, },
}, },
HTML: { HTML: {
inline: ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => { inline: ({
calLink,
uiInstructionCode,
previewState,
}: {
calLink: string;
uiInstructionCode: string;
previewState: PreviewState;
}) => {
return code`Cal("inline", { return code`Cal("inline", {
elementOrSelector:"#my-cal-inline", elementOrSelector:"#my-cal-inline",
calLink: "${calLink}" calLink: "${calLink}",
layout: "${previewState.layout}"
}); });
${uiInstructionCode}`; ${uiInstructionCode}`;
@@ -240,8 +280,22 @@ ${uiInstructionCode}`;
return code`Cal("floatingButton", ${floatingButtonArg}); return code`Cal("floatingButton", ${floatingButtonArg});
${uiInstructionCode}`; ${uiInstructionCode}`;
}, },
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => { "element-click": ({
return code`// Important: Make sure to add \`data-cal-link="${calLink}"\` attribute to the element you want to open Cal on click calLink,
uiInstructionCode,
previewState,
}: {
calLink: string;
uiInstructionCode: string;
previewState: PreviewState;
}) => {
return code`
// Important: Please add following attributes to the element you want to open Cal on click
// \`data-cal-link="${calLink}"\`
// \`data-cal-config='${JSON.stringify({
layout: previewState.layout,
})}'\`
${uiInstructionCode}`; ${uiInstructionCode}`;
}, },
}, },
@@ -298,6 +352,7 @@ const getEmbedTypeSpecificString = ({
} else if (embedType === "floating-popup") { } else if (embedType === "floating-popup") {
const floatingButtonArg = { const floatingButtonArg = {
calLink, calLink,
...(IS_SELF_HOSTED ? { calOrigin: EMBED_CAL_ORIGIN } : null),
...previewState.floatingPopup, ...previewState.floatingPopup,
}; };
return frameworkCodes[embedType]({ return frameworkCodes[embedType]({
@@ -710,13 +765,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
height: "100%", height: "100%",
}, },
theme: Theme.auto, theme: Theme.auto,
layout: BookerLayouts.MONTH_VIEW,
floatingPopup: {}, floatingPopup: {},
elementClick: {}, elementClick: {},
hideEventTypeDetails: false, hideEventTypeDetails: false,
palette: { palette: {
brandColor: "#000000", brandColor: "#000000",
}, },
layout: BookerLayouts.MONTH_VIEW,
}); });
const close = () => { const close = () => {
@@ -778,8 +833,8 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
name: "ui", name: "ui",
arg: { arg: {
theme: previewState.theme, theme: previewState.theme,
hideEventTypeDetails: previewState.hideEventTypeDetails,
layout: previewState.layout, layout: previewState.layout,
hideEventTypeDetails: previewState.hideEventTypeDetails,
styles: { styles: {
branding: { branding: {
...previewState.palette, ...previewState.palette,
@@ -1000,7 +1055,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</div> </div>
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}> <div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
<div className="whitespace-nowrap">Text color</div> <div className="whitespace-nowrap">Text color</div>
<div className="mt-2 mb-6 w-40 xl:mt-0 xl:w-full"> <div className="mb-6 mt-2 w-40 xl:mt-0 xl:w-full">
<ColorPicker <ColorPicker
className="w-[130px]" className="w-[130px]"
popoverAlign="start" popoverAlign="start"
@@ -1102,8 +1157,15 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
return; return;
} }
setPreviewState((previewState) => { setPreviewState((previewState) => {
const config = {
...(previewState.floatingPopup.config ?? {}),
layout: option.value,
};
return { return {
...previewState, ...previewState,
floatingPopup: {
config,
},
layout: option.value, layout: option.value,
}; };
}); });
+1 -1
View File
@@ -71,7 +71,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
isCurrent isCurrent
? "text-emphasis border-gray-900" ? "text-emphasis border-gray-900"
: "hover:border-default hover:text-default text-subtle border-transparent", : "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 px-1 py-4 text-sm font-medium",
className className
)} )}
aria-current={isCurrent ? "page" : undefined}> aria-current={isCurrent ? "page" : undefined}>
+7 -7
View File
@@ -85,7 +85,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 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"> <div className="align-center bg-subtle -ml-4 -mr-4 mb-4 flex min-h-[450px] w-auto basis-3/5 snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap p-4 md:-ml-8 md:-mr-8 md:mb-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" ? (
@@ -260,7 +260,7 @@ const Component = ({
)} )}
</span> </span>
<h4 className="text-emphasis mt-8 mb-2 font-semibold ">{t("contact")}</h4> <h4 className="text-emphasis mb-2 mt-8 font-semibold ">{t("contact")}</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>
@@ -269,7 +269,7 @@ const Component = ({
rel="noreferrer" rel="noreferrer"
className="text-emphasis text-sm font-normal no-underline hover:underline" className="text-emphasis text-sm font-normal no-underline hover:underline"
href={docs}> href={docs}>
<BookOpen className="text-subtle mr-1 -mt-1 inline h-4 w-4" /> <BookOpen className="text-subtle -mt-1 mr-1 inline h-4 w-4" />
{t("documentation")} {t("documentation")}
</a> </a>
</li> </li>
@@ -281,7 +281,7 @@ const Component = ({
rel="noreferrer" rel="noreferrer"
className="text-emphasis font-normal no-underline hover:underline" className="text-emphasis font-normal no-underline hover:underline"
href={website}> href={website}>
<ExternalLink className="text-subtle mr-1 -mt-px inline h-4 w-4" /> <ExternalLink className="text-subtle -mt-px mr-1 inline h-4 w-4" />
{website.replace("https://", "")} {website.replace("https://", "")}
</a> </a>
</li> </li>
@@ -293,7 +293,7 @@ const Component = ({
rel="noreferrer" rel="noreferrer"
className="text-emphasis font-normal no-underline hover:underline" className="text-emphasis font-normal no-underline hover:underline"
href={"mailto:" + email}> href={"mailto:" + email}>
<Mail className="text-subtle mr-1 -mt-px inline h-4 w-4" /> <Mail className="text-subtle -mt-px mr-1 inline h-4 w-4" />
{email} {email}
</a> </a>
@@ -306,7 +306,7 @@ const Component = ({
rel="noreferrer" rel="noreferrer"
className="text-emphasis font-normal no-underline hover:underline" className="text-emphasis font-normal no-underline hover:underline"
href={tos}> href={tos}>
<File className="text-subtle mr-1 -mt-px inline h-4 w-4" /> <File className="text-subtle -mt-px mr-1 inline h-4 w-4" />
{t("terms_of_service")} {t("terms_of_service")}
</a> </a>
</li> </li>
@@ -318,7 +318,7 @@ const Component = ({
rel="noreferrer" rel="noreferrer"
className="text-emphasis font-normal no-underline hover:underline" className="text-emphasis font-normal no-underline hover:underline"
href={privacy}> href={privacy}>
<Shield className="text-subtle mr-1 -mt-px inline h-4 w-4" /> <Shield className="text-subtle -mt-px mr-1 inline h-4 w-4" />
{t("privacy_policy")} {t("privacy_policy")}
</a> </a>
</li> </li>
@@ -28,8 +28,8 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
{emptyStore ? ( {emptyStore ? (
<EmptyScreen <EmptyScreen
Icon={AlertCircle} Icon={AlertCircle}
headline={t("no_apps")} headline={isAdmin ? t("no_apps") : t("no_apps_configured")}
description={isAdmin ? "You can enable apps in the settings" : ""} description={isAdmin ? t("enable_in_settings") : t("please_contact_admin")}
buttonText={isAdmin ? t("apps_settings") : ""} buttonText={isAdmin ? t("apps_settings") : ""}
buttonOnClick={() => router.push("/settings/admin/apps/calendar")} buttonOnClick={() => router.push("/settings/admin/apps/calendar")}
/> />
@@ -1,6 +1,4 @@
import { z } from "zod"; import { getEventLocationType, getTranslatedLocation } from "@calcom/app-store/locations";
import { getEventLocationType, locationKeyToString } from "@calcom/app-store/locations";
import { classNames } from "@calcom/lib"; import { classNames } from "@calcom/lib";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Tooltip } from "@calcom/ui"; import { Tooltip } from "@calcom/ui";
@@ -23,20 +21,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
return null; return null;
} }
const translateAbleKeys = [ const translatedLocation = getTranslatedLocation(location, eventLocationType, t);
"in_person_attendee_address",
"in_person",
"attendee_phone_number",
"link_meeting",
"organizer_phone_number",
];
const locationKey = z.string().default("").parse(locationKeyToString(location));
const translatedLocation = location.type.startsWith("integrations:")
? eventLocationType.label
: translateAbleKeys.includes(locationKey)
? t(locationKey)
: locationKey;
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">
@@ -83,7 +83,7 @@ const BookingDescription: FC<Props> = (props) => {
size="sm" size="sm"
truncateAfter={3} truncateAfter={3}
/> />
<h2 className="text-default mt-1 mb-2 break-words text-sm font-medium "> <h2 className="text-default mb-2 mt-1 break-words text-sm font-medium ">
{eventType.team?.parent?.name} {profile.name} {eventType.team?.parent?.name} {profile.name}
</h2> </h2>
<h1 className="font-cal text-emphasis mb-6 break-words text-2xl font-semibold leading-none"> <h1 className="font-cal text-emphasis mb-6 break-words text-2xl font-semibold leading-none">
@@ -19,7 +19,7 @@ const BookingDescriptionPayment = (props: {
return ( return (
<p className="text-bookinglight -ml-2 px-2 text-sm "> <p className="text-bookinglight -ml-2 px-2 text-sm ">
<CreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" /> <CreditCard className="-mt-1 ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{paymentAppData.paymentOption === "HOLD" ? ( {paymentAppData.paymentOption === "HOLD" ? (
<>{props.t("no_show_fee_amount", params)}</> <>{props.t("no_show_fee_amount", params)}</>
) : ( ) : (
@@ -374,7 +374,7 @@ function BookingListItem(booking: BookingItemProps) {
</td> </td>
<td className={"w-full px-4" + (isRejected ? " line-through" : "")} onClick={onClickTableData}> <td className={"w-full px-4" + (isRejected ? " line-through" : "")} onClick={onClickTableData}>
{/* Time and Badges for mobile */} {/* Time and Badges for mobile */}
<div className="w-full pt-4 pb-2 sm:hidden"> <div className="w-full pb-2 pt-4 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-emphasis text-sm leading-6">{startTime}</div> <div className="text-emphasis text-sm leading-6">{startTime}</div>
<div className="text-subtle pr-2 text-sm"> <div className="text-subtle pr-2 text-sm">
@@ -423,7 +423,7 @@ function BookingListItem(booking: BookingItemProps) {
<span> </span> <span> </span>
{paymentAppData.enabled && !booking.paid && booking.payment.length && ( {paymentAppData.enabled && !booking.paid && booking.payment.length && (
<Badge className="ms-2 me-2 hidden sm:inline-flex" variant="orange"> <Badge className="me-2 ms-2 hidden sm:inline-flex" variant="orange">
{t("pending_payment")} {t("pending_payment")}
</Badge> </Badge>
)} )}
@@ -64,7 +64,7 @@ export default function CancelBooking(props: Props) {
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="mt-2 mb-4 w-full " className="mb-4 mt-2 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 ">
@@ -25,7 +25,7 @@ function SkeletonItem() {
</div> </div>
</div> </div>
</div> </div>
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 lg:flex"> <div className="mt-4 hidden flex-shrink-0 sm:ml-5 sm:mt-0 lg:flex">
<div className="flex justify-between space-x-2 rtl:space-x-reverse"> <div className="flex justify-between space-x-2 rtl:space-x-reverse">
<SkeletonText className="h-6 w-16" /> <SkeletonText className="h-6 w-16" />
<SkeletonText className="h-6 w-32" /> <SkeletonText className="h-6 w-32" />
@@ -191,9 +191,9 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
)} )}
{!rescheduleUid && eventType.recurringEvent && ( {!rescheduleUid && eventType.recurringEvent && (
<div className="flex items-start text-sm font-medium"> <div className="flex items-start text-sm font-medium">
<RefreshCcw className="float-left mt-[7px] ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " /> <RefreshCcw className="float-left ml-[2px] mt-[7px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
<div> <div>
<p className="mb-1 -ml-2 inline px-2 py-1"> <p className="-ml-2 mb-1 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })} {getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
</p> </p>
@@ -218,7 +218,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
)} )}
{paymentAppData.price > 0 && ( {paymentAppData.price > 0 && (
<p className="-ml-2 px-2 text-sm font-medium"> <p className="-ml-2 px-2 text-sm font-medium">
<CreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" /> <CreditCard className="-mt-1 ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{paymentAppData.paymentOption === "HOLD" ? ( {paymentAppData.paymentOption === "HOLD" ? (
<> <>
{t("no_show_fee_amount", { {t("no_show_fee_amount", {
@@ -534,7 +534,7 @@ const BookingPage = ({
)}> )}>
<div className="sm:flex"> <div className="sm:flex">
{showEventTypeDetails && ( {showEventTypeDetails && (
<div className="sm:border-subtle text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6"> <div className="sm:border-subtle text-default flex flex-col px-6 pb-0 pt-6 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} t={t} i18n={i18n} /> <BookingDescriptionPayment eventType={eventType} t={t} i18n={i18n} />
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && ( {!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
@@ -561,7 +561,7 @@ const BookingPage = ({
recurringStrings.slice(0, 5).map((timeFormatted, key) => { recurringStrings.slice(0, 5).map((timeFormatted, key) => {
return <p key={key}>{timeFormatted}</p>; return <p key={key}>{timeFormatted}</p>;
})} })}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && ( {!rescheduleUid && eventType?.recurringEvent?.freq && recurringStrings.length > 5 && (
<div className="flex"> <div className="flex">
<Tooltip <Tooltip
content={recurringStrings.slice(5).map((timeFormatted, key) => ( content={recurringStrings.slice(5).map((timeFormatted, key) => (
@@ -577,11 +577,11 @@ const BookingPage = ({
</div> </div>
{booking?.startTime && rescheduleUid && ( {booking?.startTime && rescheduleUid && (
<div> <div>
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p"> <p className="mb-2 mt-8 text-sm " data-testid="former_time_p">
{t("former_time")} {t("former_time")}
</p> </p>
<p className="line-through "> <p className="line-through ">
<Calendar className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" /> <Calendar className="-mt-1 ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{isClientTimezoneAvailable && {isClientTimezoneAvailable &&
typeof booking.startTime === "string" && typeof booking.startTime === "string" &&
parseDateTimeWithTimeZone(booking.startTime, i18n.language, timezone, { parseDateTimeWithTimeZone(booking.startTime, i18n.language, timezone, {
@@ -259,7 +259,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
{booking && ( {booking && (
<> <>
<p className="text-emphasis mt-6 mb-2 ml-1 text-sm font-bold">{t("current_location")}:</p> <p className="text-emphasis mb-2 ml-1 mt-6 text-sm font-bold">{t("current_location")}:</p>
<p className="text-emphasis mb-2 ml-1 text-sm"> <p className="text-emphasis mb-2 ml-1 text-sm">
{getHumanReadableLocationValue(booking.location, t)} {getHumanReadableLocationValue(booking.location, t)}
</p> </p>
@@ -49,7 +49,7 @@ export const RescheduleDialog = (props: IRescheduleDialog) => {
<div className="pt-1"> <div className="pt-1">
<DialogHeader title={t("send_reschedule_request")} /> <DialogHeader title={t("send_reschedule_request")} />
<p className="text-subtle text-sm">{t("reschedule_modal_description")}</p> <p className="text-subtle text-sm">{t("reschedule_modal_description")}</p>
<p className="text-emphasis mt-6 mb-2 text-sm font-bold"> <p className="text-emphasis mb-2 mt-6 text-sm font-bold">
{t("reason_for_reschedule_request")} {t("reason_for_reschedule_request")}
<span className="text-subtle font-normal"> (Optional)</span> <span className="text-subtle font-normal"> (Optional)</span>
</p> </p>
+1 -1
View File
@@ -35,7 +35,7 @@ const ErrorDebugPanel: React.FC<{ error: Props["error"]; children?: never }> = (
{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:px-6 sm:py-5">
<dt className="text-emphasis text-sm font-bold">{key}</dt> <dt className="text-emphasis text-sm font-bold">{key}</dt>
<dd className="text-emphasis mt-1 text-sm 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>
@@ -84,7 +84,7 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
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="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"> <div className="bg-subtle ml-11 mt-3 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="text-emphasis overflow-hidden text-ellipsis p-1.5 font-medium">{previewText}</p> <p className="text-emphasis overflow-hidden text-ellipsis p-1.5 font-medium">{previewText}</p>
<p className="text-default ml-1.5 text-[10px] font-normal">8 - 10 AM</p> <p className="text-default ml-1.5 text-[10px] font-normal">8 - 10 AM</p>
</div> </div>
@@ -38,6 +38,7 @@ const generateHashedLink = (id: number) => {
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => { export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => {
const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery(); const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery();
const { data: user } = trpc.viewer.me.useQuery();
const formMethods = useFormContext<FormValues>(); const formMethods = useFormContext<FormValues>();
const { t } = useLocale(); const { t } = useLocale();
@@ -49,6 +50,9 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const bookingFields: Prisma.JsonObject = {}; const bookingFields: Prisma.JsonObject = {};
const workflows = eventType.workflows.map((workflowOnEventType) => workflowOnEventType.workflow); const workflows = eventType.workflows.map((workflowOnEventType) => workflowOnEventType.workflow);
const selectedThemeIsDark =
user?.theme === "dark" ||
(!user?.theme && typeof document !== "undefined" && document.documentElement.classList.contains("dark"));
eventType.bookingFields.forEach(({ name }) => { eventType.bookingFields.forEach(({ name }) => {
bookingFields[name] = name + " input"; bookingFields[name] = name + " input";
@@ -153,7 +157,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
color="minimal" color="minimal"
size="sm" size="sm"
aria-label="edit custom name" aria-label="edit custom name"
className="hover:stroke-3 hover:text-emphasis min-w-fit px-0 !py-0 hover:bg-transparent" className="hover:stroke-3 hover:text-emphasis min-w-fit !py-0 px-0 hover:bg-transparent"
onClick={() => setShowEventNameTip((old) => !old)}> onClick={() => setShowEventNameTip((old) => !old)}>
<Edit className="h-4 w-4" /> <Edit className="h-4 w-4" />
</Button> </Button>
@@ -162,7 +166,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
</div> </div>
<hr className="border-subtle [&:has(+div:empty)]:hidden" /> <hr className="border-subtle [&:has(+div:empty)]:hidden" />
<div> <div>
<BookerLayoutSelector fallbackToUserSettings /> <BookerLayoutSelector fallbackToUserSettings isDark={selectedThemeIsDark} />
</div> </div>
<hr className="border-subtle" /> <hr className="border-subtle" />
<FormBuilder <FormBuilder
@@ -216,7 +220,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
onChange(e ? value : ""); onChange(e ? value : "");
}}> }}>
{/* Textfield has some margin by default we remove that so we can keep consistent alignment */} {/* Textfield has some margin by default we remove that so we can keep consistent alignment */}
<div className="lg:-ml-2 lg:-mb-2"> <div className="lg:-mb-2 lg:-ml-2">
<TextField <TextField
className="w-full" className="w-full"
label={t("redirect_success_booking")} label={t("redirect_success_booking")}
@@ -268,7 +272,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
color="minimal" color="minimal"
size="sm" size="sm"
type="button" type="button"
className="hover:stroke-3 hover:text-emphasis min-w-fit px-0 !py-0 hover:bg-transparent" className="hover:stroke-3 hover:text-emphasis min-w-fit !py-0 px-0 hover:bg-transparent"
aria-label="copy link" aria-label="copy link"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(placeholderHashedLink); navigator.clipboard.writeText(placeholderHashedLink);
@@ -171,7 +171,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
return ( return (
<div className="space-y-8"> <div className="space-y-8">
<div className="space-y-4 lg:space-y-8"> <div className="space-y-4 lg:space-y-8">
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4"> <div className="flex flex-col space-y-4 lg:flex-row lg:space-x-4 lg:space-y-0">
<div className="w-full"> <div className="w-full">
<Label htmlFor="beforeBufferTime"> <Label htmlFor="beforeBufferTime">
{t("before_event")} {t("before_event")}
@@ -245,7 +245,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
/> />
</div> </div>
</div> </div>
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4"> <div className="flex flex-col space-y-4 lg:flex-row lg:space-x-4 lg:space-y-0">
<div className="w-full"> <div className="w-full">
<Label htmlFor="minimumBookingNotice"> <Label htmlFor="minimumBookingNotice">
{t("minimum_booking_notice")} {t("minimum_booking_notice")}
@@ -416,7 +416,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
</div> </div>
)} )}
{period.type === "RANGE" && ( {period.type === "RANGE" && (
<div className="ms-2 me-2 inline-flex space-x-2 rtl:space-x-reverse"> <div className="me-2 ms-2 inline-flex space-x-2 rtl:space-x-reverse">
<Controller <Controller
name="periodDates" name="periodDates"
control={formMethods.control} control={formMethods.control}
@@ -437,7 +437,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
/> />
</div> </div>
)} )}
{period.suffix ? <span className="ms-2 me-2">&nbsp;{period.suffix}</span> : null} {period.suffix ? <span className="me-2 ms-2">&nbsp;{period.suffix}</span> : null}
</div> </div>
); );
})} })}
@@ -284,7 +284,7 @@ export const EventSetupTab = (
return ( return (
<li <li
key={`${location.type}${index}`} key={`${location.type}${index}`}
className="border-default text-default mb-2 h-9 rounded-md border py-1.5 px-2 hover:cursor-pointer"> className="border-default text-default mb-2 h-9 rounded-md border px-2 py-1.5 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
@@ -298,7 +298,7 @@ export const EventSetupTab = (
)} )}
alt={`${eventLocationType.label} logo`} alt={`${eventLocationType.label} logo`}
/> />
<span className="line-clamp-1 ms-1 text-sm">{eventLabel}</span> <span className="ms-1 line-clamp-1 text-sm">{eventLabel}</span>
</div> </div>
<div className="flex"> <div className="flex">
<button <button
@@ -332,7 +332,7 @@ export const EventSetupTab = (
location.type === MeetLocationType && destinationCalendar?.integration !== "google_calendar" location.type === MeetLocationType && destinationCalendar?.integration !== "google_calendar"
) && ( ) && (
<div className="text-default flex text-sm"> <div className="text-default flex text-sm">
<Check className="mt-0.5 mr-1.5 h-2 w-2.5" /> <Check className="mr-1.5 mt-0.5 h-2 w-2.5" />
<Trans i18nKey="event_type_requres_google_cal"> <Trans i18nKey="event_type_requres_google_cal">
<p> <p>
The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work. The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work.
@@ -369,7 +369,7 @@ function EventTypeSingleLayout({
</DropdownItem> </DropdownItem>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<div className="hover:bg-subtle flex h-9 cursor-pointer flex-row items-center justify-between py-2 px-4"> <div className="hover:bg-subtle flex h-9 cursor-pointer flex-row items-center justify-between px-4 py-2">
<Skeleton <Skeleton
as={Label} as={Label}
htmlFor="hiddenSwitch" htmlFor="hiddenSwitch"
@@ -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">
<Clock className="text-subtle mt-0.5 mr-1.5 inline h-4 w-4" /> <Clock className="text-subtle mr-1.5 mt-0.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">
<User className="text-subtle mt-0.5 mr-1.5 inline h-4 w-4" /> <User className="text-subtle mr-1.5 mt-0.5 inline h-4 w-4" />
<SkeletonText className="h-4 w-12" /> <SkeletonText className="h-4 w-12" />
</li> </li>
</ul> </ul>
@@ -3,7 +3,7 @@ import { useForm } from "react-hook-form";
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode"; import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Dialog, DialogContent, Form, Label, PasswordField } from "@calcom/ui"; import { Button, Dialog, DialogContent, Form, PasswordField } from "@calcom/ui";
import TwoFactor from "@components/auth/TwoFactor"; import TwoFactor from "@components/auth/TwoFactor";
@@ -75,14 +75,12 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
{...form.register("password")} {...form.register("password")}
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" 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>
<TwoFactor center={false} /> <TwoFactor center={false} />
{errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>} {errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>}
</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="ms-2 me-2" disabled={isDisabling}> <Button type="submit" className="me-2 ms-2" disabled={isDisabling}>
{t("disable")} {t("disable")}
</Button> </Button>
<Button color="secondary" onClick={onCancel}> <Button color="secondary" onClick={onCancel}>
@@ -19,7 +19,7 @@ const DisableUserImpersonation = ({ disableImpersonation }: { disableImpersonati
return ( return (
<> <>
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row"> <div className="flex flex-col justify-between pl-2 pt-9 sm:flex-row">
<div> <div>
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<h2 className="font-cal text-emphasis text-lg font-medium leading-6"> <h2 className="font-cal text-emphasis text-lg font-medium leading-6">
@@ -178,19 +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="ms-2 me-2" className="me-2 ms-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 type="submit" className="ms-2 me-2" onClick={() => setStep(SetupStep.EnterTotpCode)}> <Button type="submit" className="me-2 ms-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="ms-2 me-2" disabled={isSubmitting}> <Button type="submit" className="me-2 ms-2" disabled={isSubmitting}>
{t("enable")} {t("enable")}
</Button> </Button>
</WithStep> </WithStep>
@@ -14,7 +14,7 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
return ( return (
<> <>
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row"> <div className="flex flex-col justify-between pl-2 pt-9 sm:flex-row">
<div> <div>
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<h2 className="font-cal text-emphasis text-lg font-medium leading-6">{t("2fa")}</h2> <h2 className="font-cal text-emphasis text-lg font-medium leading-6">{t("2fa")}</h2>
@@ -6,7 +6,7 @@ const TwoFactorModalHeader = ({ title, description }: { title: string; descripti
<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">
<Shield className="text-inverted h-6 w-6" /> <Shield 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:ml-4 sm:mt-0 sm:text-left">
<h3 className="font-cal text-emphasis text-lg font-medium leading-6" id="modal-title"> <h3 className="font-cal text-emphasis text-lg font-medium leading-6" id="modal-title">
{title} {title}
</h3> </h3>
@@ -3,7 +3,7 @@ import { useForm } from "react-hook-form";
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode"; import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Dialog, DialogContent, Form, Label, PasswordField } from "@calcom/ui"; import { Button, Dialog, DialogContent, Form, PasswordField } from "@calcom/ui";
import TwoFactor from "@components/auth/TwoFactor"; import TwoFactor from "@components/auth/TwoFactor";
@@ -82,15 +82,13 @@ const DisableTwoFactorAuthModal = ({
{...form.register("password")} {...form.register("password")}
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" 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>
<TwoFactor center={false} /> <TwoFactor center={false} />
{errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>} {errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>}
</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="ms-2 me-2" data-testid="disable-2fa" disabled={isDisabling}> <Button type="submit" className="me-2 ms-2" data-testid="disable-2fa" disabled={isDisabling}>
{t("disable")} {t("disable")}
</Button> </Button>
<Button color="secondary" onClick={onCancel}> <Button color="secondary" onClick={onCancel}>
@@ -177,7 +177,7 @@ 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="ms-2 me-2" className="me-2 ms-2"
onClick={handleSetup} onClick={handleSetup}
disabled={password.length === 0 || isSubmitting}> disabled={password.length === 0 || isSubmitting}>
{t("continue")} {t("continue")}
@@ -187,13 +187,13 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
<Button <Button
type="submit" type="submit"
data-testid="goto-otp-screen" data-testid="goto-otp-screen"
className="ms-2 me-2" className="me-2 ms-2"
onClick={() => setStep(SetupStep.EnterTotpCode)}> 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="ms-2 me-2" data-testid="enable-2fa" disabled={isSubmitting}> <Button type="submit" className="me-2 ms-2" data-testid="enable-2fa" disabled={isSubmitting}>
{t("enable")} {t("enable")}
</Button> </Button>
</WithStep> </WithStep>
+1 -1
View File
@@ -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 bg-subtle border-default text-subtle mt-2 inline-flex rounded-t-md border border-b-0 py-1 px-3"> <small className="items-centerpx-3 bg-subtle border-default text-subtle mt-2 inline-flex rounded-t-md border border-b-0 px-3 py-1">
{process.env.NEXT_PUBLIC_WEBSITE_URL} {process.env.NEXT_PUBLIC_WEBSITE_URL}
</small> </small>
)} )}
+1 -1
View File
@@ -27,7 +27,7 @@ const StepDone = (props: {
<Check className="text-inverted dark:bg-default dark:text-default inline-block h-10 w-10" /> <Check 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="mb-1 mt-6 text-lg font-medium dark:text-gray-300">{t("all_done")}</h2>
</div> </div>
</div> </div>
</form> </form>
+2 -2
View File
@@ -30,9 +30,9 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
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="mt-2 line-clamp-4 w-full space-y-1">
<p className="text-default font-medium">{member.name}</p> <p className="text-default font-medium">{member.name}</p>
<div className="line-clamp-3 text-subtle overflow-ellipsis text-sm font-normal"> <div className="text-subtle line-clamp-3 overflow-ellipsis text-sm font-normal">
{!isBioEmpty ? ( {!isBioEmpty ? (
<> <>
<div <div
+2 -2
View File
@@ -23,7 +23,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}&nbsp;</span> <span className="whitespace-pre text-xl tracking-normal text-transparent">{value}&nbsp;</span>
{!isEditing && isReady && ( {!isEditing && isReady && (
<Edit2 className=" text-subtle group-hover:text-subtle ml-1 -mt-px inline h-3 w-3" /> <Edit2 className=" text-subtle group-hover:text-subtle -mt-px ml-1 inline h-3 w-3" />
)} )}
<input <input
{...passThroughProps} {...passThroughProps}
@@ -31,7 +31,7 @@ const EditableHeading = function EditableHeading({
value={value} value={value}
required required
className={classNames( className={classNames(
"text-emphasis hover:text-default focus:text-emphasis absolute top-0 left-0 w-full cursor-pointer truncate border-none bg-transparent p-0 align-top text-xl focus:outline-none focus:ring-0" "text-emphasis hover:text-default focus:text-emphasis absolute left-0 top-0 w-full cursor-pointer truncate border-none bg-transparent p-0 align-top text-xl focus:outline-none focus:ring-0"
)} )}
onFocus={(e) => { onFocus={(e) => {
setIsEditing(true); setIsEditing(true);
+1 -1
View File
@@ -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}>
<Info className="text-subtle relative top-px left-1 right-1 mt-px h-4 w-4" /> <Info className="text-subtle relative left-1 right-1 top-px mt-px h-4 w-4" />
</span> </span>
</Tooltip> </Tooltip>
</> </>
+1 -1
View File
@@ -14,7 +14,7 @@ export default function ModalContainer(
}> }>
) { ) {
return ( return (
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0"> <div className="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<Dialog open={props.isOpen} onOpenChange={props.onExit}> <Dialog open={props.isOpen} onOpenChange={props.onExit}>
<DialogContent> <DialogContent>
<div <div
@@ -224,7 +224,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
}} }}
data-testid="username-input" data-testid="username-input"
/> />
<div className="absolute top-0 right-2 flex flex-row"> <div className="absolute right-2 top-0 flex flex-row">
<span <span
className={classNames( className={classNames(
"mx-2 py-2", "mx-2 py-2",
@@ -80,7 +80,7 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
const ActionButtons = () => { const ActionButtons = () => {
return usernameIsAvailable && currentUsername !== inputUsernameValue ? ( return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
<div className="ms-2 me-2 flex flex-row space-x-2"> <div className="me-2 ms-2 flex flex-row space-x-2">
<Button <Button
type="button" type="button"
onClick={() => setOpenDialogSaveUsername(true)} onClick={() => setOpenDialogSaveUsername(true)}
+2 -1
View File
@@ -5,7 +5,8 @@ import type { GetServerSidePropsContext } from "next";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import type { Maybe } from "@calcom/trpc/server"; import type { Maybe } from "@calcom/trpc/server";
import { i18n } from "../../../next-i18next.config"; // eslint-disable-next-line @typescript-eslint/no-var-requires
const { i18n } = require("@calcom/config/next-i18next.config");
export function getLocaleFromHeaders(req: IncomingMessage): string { export function getLocaleFromHeaders(req: IncomingMessage): string {
let preferredLocale: string | null | undefined; let preferredLocale: string | null | undefined;
-30
View File
@@ -3,7 +3,6 @@ import { collectEvents } from "next-collect/server";
import type { NextMiddleware } from "next/server"; import type { NextMiddleware } from "next/server";
import { NextResponse, userAgent } from "next/server"; import { NextResponse, userAgent } from "next/server";
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { CONSOLE_URL, WEBAPP_URL, WEBSITE_URL } from "@calcom/lib/constants"; import { CONSOLE_URL, WEBAPP_URL, WEBSITE_URL } from "@calcom/lib/constants";
import { isIpInBanlist } from "@calcom/lib/getIP"; import { isIpInBanlist } from "@calcom/lib/getIP";
import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry"; import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry";
@@ -11,20 +10,11 @@ import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry
const middleware: NextMiddleware = async (req) => { const middleware: NextMiddleware = async (req) => {
const url = req.nextUrl; const url = req.nextUrl;
const requestHeaders = new Headers(req.headers); const requestHeaders = new Headers(req.headers);
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(req.headers.get("host") ?? "");
/** /**
* We are using env variable to toggle new-booker because using flags would be an unnecessary delay for booking pages * We are using env variable to toggle new-booker because using flags would be an unnecessary delay for booking pages
* Also, we can't easily identify the booker page requests here(to just fetch the flags for those requests) * Also, we can't easily identify the booker page requests here(to just fetch the flags for those requests)
*/ */
// Make sure we are in the presence of an organization
if (isValidOrgDomain && url.pathname === "/") {
// In the presence of an organization, cover its profile page at "/"
// rewrites for org profile page using team profile page
url.pathname = `/org/${currentOrgDomain}`;
return NextResponse.rewrite(url);
}
if (isIpInBanlist(req) && url.pathname !== "/api/nope") { if (isIpInBanlist(req) && url.pathname !== "/api/nope") {
// DDOS Prevention: Immediately end request with no response - Avoids a redirect as well initiated by NextAuth on invalid callback // DDOS Prevention: Immediately end request with no response - Avoids a redirect as well initiated by NextAuth on invalid callback
req.nextUrl.pathname = "/api/nope"; req.nextUrl.pathname = "/api/nope";
@@ -83,26 +73,6 @@ const middleware: NextMiddleware = async (req) => {
requestHeaders.set("x-csp-enforce", "true"); requestHeaders.set("x-csp-enforce", "true");
} }
if (isValidOrgDomain) {
// Match /:slug to determine if it corresponds to org subteam slug or org user slug
const slugs = /^\/([^/]+)(\/[^/]+)?$/.exec(url.pathname);
// In the presence of an organization, if not team profile, a user or team is being accessed
if (slugs) {
const [_, teamName, eventType] = slugs;
// Fetch the corresponding subteams for the entered organization
const getSubteams = await fetch(`${WEBAPP_URL}/api/organizations/${currentOrgDomain}/subteams`);
if (getSubteams.ok) {
const data = await getSubteams.json();
// Treat entered slug as a team if found in the subteams fetched
if (data.slugs.includes(teamName)) {
// Rewriting towards /team/:slug to bring up the team profile within the org
url.pathname = `/team/${teamName}${eventType ?? ""}`;
return NextResponse.rewrite(url);
}
}
}
}
return NextResponse.next({ return NextResponse.next({
request: { request: {
headers: requestHeaders, headers: requestHeaders,
+68 -27
View File
@@ -1,10 +1,10 @@
require("dotenv").config({ path: "../../.env" }); require("dotenv").config({ path: "../../.env" });
const CopyWebpackPlugin = require("copy-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin");
const os = require("os"); const os = require("os");
const glob = require("glob");
const englishTranslation = require("./public/static/locales/en/common.json"); const englishTranslation = require("./public/static/locales/en/common.json");
const { withAxiom } = require("next-axiom"); const { withAxiom } = require("next-axiom");
const { i18n } = require("./next-i18next.config"); const { i18n } = require("./next-i18next.config");
const { pages } = require("./pages");
if (!process.env.NEXTAUTH_SECRET) throw new Error("Please set NEXTAUTH_SECRET"); if (!process.env.NEXTAUTH_SECRET) throw new Error("Please set NEXTAUTH_SECRET");
if (!process.env.CALENDSO_ENCRYPTION_KEY) throw new Error("Please set CALENDSO_ENCRYPTION_KEY"); if (!process.env.CALENDSO_ENCRYPTION_KEY) throw new Error("Please set CALENDSO_ENCRYPTION_KEY");
@@ -71,6 +71,13 @@ const informAboutDuplicateTranslations = () => {
informAboutDuplicateTranslations(); informAboutDuplicateTranslations();
const getSubdomain = () => {
const _url = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL);
const regex = new RegExp(/^([a-z]+\:\/{2})?((?<subdomain>[\w-]+)\.[\w-]+\.\w+)$/);
//console.log(_url.hostname, _url.hostname.match(regex));
return _url.hostname.match(regex)?.groups?.subdomain || null;
};
const plugins = []; const plugins = [];
if (process.env.ANALYZE === "true") { if (process.env.ANALYZE === "true") {
// only load dependency if env `ANALYZE` was set // only load dependency if env `ANALYZE` was set
@@ -82,16 +89,19 @@ if (process.env.ANALYZE === "true") {
plugins.push(withAxiom); plugins.push(withAxiom);
/** Needed to rewrite public booking page, gets all static pages but [user] */ // .* matches / as well(Note: *(i.e wildcard) doesn't match / but .*(i.e. RegExp) does)
const pages = glob // It would match /free/30min but not /bookings/upcoming because 'bookings' is an item in pages
.sync("pages/**/[^_]*.{tsx,js,ts}", { cwd: __dirname }) // It would also not match /free/30min/embed because we are ensuring just two slashes
.map((filename) => // ?!book ensures it doesn't match /free/book page which doesn't have a corresponding new-booker page.
filename // [^/]+ makes the RegExp match the full path, it seems like a partial match doesn't work.
.substr(6) // book$ ensures that only /book is excluded from rewrite(which is at the end always) and not /booked
.replace(/(\.tsx|\.js|\.ts)/, "")
.replace(/\/.*/, "") // Important Note: When modifying these RegExps update apps/web/test/lib/next-config.test.ts as well
) const userTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type((?!book$)[^/]+)`;
.filter((v, i, self) => self.indexOf(v) === i && !v.startsWith("[user]")); const teamTypeRouteRegExp = "/team/:slug/:type((?!book$)[^/]+)";
const privateLinkRouteRegExp = "/d/:link/:slug((?!book$)[^/]+)";
const embedUserTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type/embed`;
const embedTeamTypeRouteRegExp = "/team/:slug/:type/embed";
/** @type {import("next").NextConfig} */ /** @type {import("next").NextConfig} */
const nextConfig = { const nextConfig = {
@@ -183,15 +193,43 @@ const nextConfig = {
return config; return config;
}, },
async rewrites() { async rewrites() {
// .* matches / as well(Note: *(i.e wildcard) doesn't match / but .*(i.e. RegExp) does) const defaultSubdomain = getSubdomain();
// It would match /free/30min but not /bookings/upcoming because 'bookings' is an item in pages const subdomain = defaultSubdomain ? `(?!${defaultSubdomain})[^.]+` : "[^.]+";
// It would also not match /free/30min/embed because we are ensuring just two slashes
// ?!book ensures it doesn't match /free/book page which doesn't have a corresponding new-booker page. const beforeFiles = [
// [^/]+ makes the RegExp match the full path, it seems like a partial match doesn't work. {
const userTypeRouteRegExp = `/:user((?!${pages.join("/|")}$)[^/]*)/:type((?!book)[^/]+)`; has: [
const teamTypeRouteRegExp = "/team/:slug/:type((?!book)[^/]+)"; {
const privateLinkRouteRegExp = "/d/:link/:slug((?!book)[^/]+)"; type: "host",
let rewrites = [ value: `^(?<orgSlug>${subdomain})\\..*`,
},
],
source: "/",
destination: "/team/:orgSlug",
},
{
has: [
{
type: "host",
value: `^(?<orgSlug>${subdomain})\\..*`,
},
],
source: `/:user((?!${pages.join("|")}|_next|public)[a-zA-Z0-9\-_]+)`,
destination: "/org/:orgSlug/:user",
},
{
has: [
{
type: "host",
value: `^(?<orgSlug>${subdomain}[^.]+)\\..*`,
},
],
source: `/:user((?!${pages.join("|")}|_next|public))/:path*`,
destination: "/:user/:path*",
},
];
let afterFiles = [
{ {
source: "/org/:slug", source: "/org/:slug",
destination: "/team/:slug", destination: "/team/:slug",
@@ -248,12 +286,12 @@ const nextConfig = {
// Keep cookie based booker enabled to test new-booker embed in production // Keep cookie based booker enabled to test new-booker embed in production
...[ ...[
{ {
source: `/:user((?!${pages.join("|")}).*)/:type/embed`, source: embedUserTypeRouteRegExp,
destination: "/new-booker/:user/:type/embed", destination: "/new-booker/:user/:type/embed",
has: [{ type: "cookie", key: "new-booker-enabled" }], has: [{ type: "cookie", key: "new-booker-enabled" }],
}, },
{ {
source: "/team/:slug/:type/embed", source: embedTeamTypeRouteRegExp,
destination: "/new-booker/team/:slug/:type/embed", destination: "/new-booker/team/:slug/:type/embed",
has: [{ type: "cookie", key: "new-booker-enabled" }], has: [{ type: "cookie", key: "new-booker-enabled" }],
}, },
@@ -271,14 +309,14 @@ const nextConfig = {
// Enable New Booker for all Embed Requests // Enable New Booker for all Embed Requests
if (process.env.NEW_BOOKER_ENABLED_FOR_EMBED === "1") { if (process.env.NEW_BOOKER_ENABLED_FOR_EMBED === "1") {
console.log("Enabling New Booker for Embed"); console.log("Enabling New Booker for Embed");
rewrites.push( afterFiles.push(
...[ ...[
{ {
source: `/:user((?!${pages.join("|")}).*)/:type/embed`, source: embedUserTypeRouteRegExp,
destination: "/new-booker/:user/:type/embed", destination: "/new-booker/:user/:type/embed",
}, },
{ {
source: "/team/:slug/:type/embed", source: embedTeamTypeRouteRegExp,
destination: "/new-booker/team/:slug/:type/embed", destination: "/new-booker/team/:slug/:type/embed",
}, },
] ]
@@ -288,7 +326,7 @@ const nextConfig = {
// Enable New Booker for All but embed Requests // Enable New Booker for All but embed Requests
if (process.env.NEW_BOOKER_ENABLED_FOR_NON_EMBED === "1") { if (process.env.NEW_BOOKER_ENABLED_FOR_NON_EMBED === "1") {
console.log("Enabling New Booker for Non-Embed"); console.log("Enabling New Booker for Non-Embed");
rewrites.push( afterFiles.push(
...[ ...[
{ {
source: userTypeRouteRegExp, source: userTypeRouteRegExp,
@@ -305,7 +343,10 @@ const nextConfig = {
] ]
); );
} }
return rewrites; return {
beforeFiles,
afterFiles,
};
}, },
async headers() { async headers() {
return [ return [
+6 -7
View File
@@ -1,6 +1,6 @@
{ {
"name": "@calcom/web", "name": "@calcom/web",
"version": "3.0.4", "version": "3.0.7",
"private": true, "private": true,
"scripts": { "scripts": {
"analyze": "ANALYZE=true next build", "analyze": "ANALYZE=true next build",
@@ -48,7 +48,7 @@
"@radix-ui/react-avatar": "^1.0.0", "@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-collapsible": "^1.0.0", "@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0", "@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0", "@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-id": "^1.0.0", "@radix-ui/react-id": "^1.0.0",
"@radix-ui/react-popover": "^1.0.2", "@radix-ui/react-popover": "^1.0.2",
"@radix-ui/react-radio-group": "^1.0.0", "@radix-ui/react-radio-group": "^1.0.0",
@@ -90,10 +90,10 @@
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"next": "^13.4.6", "next": "^13.4.6",
"next-auth": "^4.20.1", "next-auth": "^4.20.1",
"next-axiom": "^0.16.0", "next-axiom": "^0.17.0",
"next-collect": "^0.2.1", "next-collect": "^0.2.1",
"next-i18next": "^11.3.0", "next-i18next": "^13.2.2",
"next-seo": "^4.26.0", "next-seo": "^6.0.0",
"next-themes": "^0.2.0", "next-themes": "^0.2.0",
"nodemailer": "^6.7.8", "nodemailer": "^6.7.8",
"otplib": "^12.0.1", "otplib": "^12.0.1",
@@ -109,7 +109,7 @@
"react-hook-form": "^7.43.3", "react-hook-form": "^7.43.3",
"react-hot-toast": "^2.3.0", "react-hot-toast": "^2.3.0",
"react-intl": "^5.25.1", "react-intl": "^5.25.1",
"react-live-chat-loader": "^2.7.3", "react-live-chat-loader": "^2.8.1",
"react-multi-email": "^0.5.3", "react-multi-email": "^0.5.3",
"react-phone-input-2": "^2.15.1", "react-phone-input-2": "^2.15.1",
"react-phone-number-input": "^3.2.7", "react-phone-number-input": "^3.2.7",
@@ -162,7 +162,6 @@
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"detect-port": "^1.3.0", "detect-port": "^1.3.0",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"mockdate": "^3.0.5",
"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",
+14
View File
@@ -0,0 +1,14 @@
const glob = require("glob");
/** Needed to rewrite public booking page, gets all static pages but [user] */
const pages = glob
.sync("pages/**/[^_]*.{tsx,js,ts}", { cwd: __dirname })
.map((filename) =>
filename
.substr(6)
.replace(/(\.tsx|\.js|\.ts)/, "")
.replace(/\/.*/, "")
)
.filter((v, i, self) => self.indexOf(v) === i && !v.startsWith("[user]"));
exports.pages = pages;
+92 -54
View File
@@ -3,22 +3,37 @@ 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 { orgDomainConfig, subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains";
import { 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 { BookOpen, Check, ChevronRight, FileText, Slack } from "@calcom/ui/components/icon"; import { BookOpen, Check, ChevronRight, FileText, Slack, Shield } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper"; import PageWrapper from "@components/PageWrapper";
import { ssgInit } from "@server/lib/ssg"; import { ssgInit } from "@server/lib/ssg";
enum pageType {
ORG = "org",
TEAM = "team",
USER = "user",
OTHER = "other",
}
export default function Custom404() { export default function Custom404() {
const { t } = useLocale(); const { t } = useLocale();
const router = useRouter(); const router = useRouter();
const [username] = router.asPath.replace("%20", "-").split(/[?#]/); const [username, setUsername] = useState<string>("");
const [currentPageType, setCurrentPageType] = useState<pageType>(pageType.USER);
const links = [ const links = [
{
title: "Enterprise",
description: "Learn more about organizations and subdomains in our enterprise plan.",
icon: Shield,
href: `${WEBSITE_URL}/enterprise`,
},
{ {
title: t("documentation"), title: t("documentation"),
description: t("documentation_description"), description: t("documentation_description"),
@@ -33,19 +48,34 @@ export default function Custom404() {
}, },
]; ];
const [url, setUrl] = useState(`${WEBSITE_URL}/signup?username=`); const [url, setUrl] = useState(`${WEBSITE_URL}/signup`);
useEffect(() => { useEffect(() => {
setUrl(`${WEBSITE_URL}/signup?username=${username.replace("/", "")}`); const { isValidOrgDomain, currentOrgDomain } = orgDomainConfig(window.location.host);
}, [username]); const [routerUsername] = router.asPath.replace("%20", "-").split(/[?#]/);
if (!isValidOrgDomain || !currentOrgDomain) {
const splitPath = routerUsername.split("/");
if (splitPath[1] === "team" && splitPath.length === 3) {
// Accessing a non-existent team
setUsername(splitPath[2]);
setCurrentPageType(pageType.TEAM);
setUrl(`${WEBSITE_URL}/signup?callbackUrl=settings/teams/new%3Fslug%3D${username.replace("/", "")}`);
} else {
setUsername(routerUsername);
setUrl(`${WEBSITE_URL}/signup?username=${username.replace("/", "")}`);
}
} else {
setUsername(currentOrgDomain);
setCurrentPageType(pageType.ORG);
setUrl(
`${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${username.replace("/", "")}`
);
}
}, []);
const isSuccessPage = router.asPath.startsWith("/booking"); const isSuccessPage = router.asPath.startsWith("/booking");
const isSubpage = router.asPath.includes("/", 2) || isSuccessPage; const isSubpage = router.asPath.includes("/", 2) || isSuccessPage;
const isSignup = router.asPath.startsWith("/signup"); const isSignup = router.asPath.startsWith("/signup");
const isCalcom = process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.com"; const isCalcom = process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.com";
// In case of invalid email verification token, we intentionally redirect to 404 from the API
const isInvalidToken = router.asPath === "/404";
/** /**
* If we're on 404 and the route is insights it means it is disabled * If we're on 404 and the route is insights it means it is disabled
* TODO: Abstract this for all disabled features * TODO: Abstract this for all disabled features
@@ -63,7 +93,7 @@ export default function Custom404() {
}} }}
/> />
<div className="min-h-screen bg-white px-4" data-testid="404-page"> <div className="min-h-screen bg-white 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 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">{t("error_404")}</p> <p className="text-sm font-semibold uppercase tracking-wide text-black">{t("error_404")}</p>
<h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 sm:text-5xl"> <h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 sm:text-5xl">
@@ -84,6 +114,8 @@ export default function Custom404() {
); );
} }
if (!username) return null;
return ( return (
<> <>
<HeadSeo <HeadSeo
@@ -95,7 +127,7 @@ export default function Custom404() {
}} }}
/> />
<div className="bg-default min-h-screen 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 pb-6 pt-16 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>
@@ -204,21 +236,15 @@ export default function Custom404() {
{t("error_404")} {t("error_404")}
</p> </p>
<h1 className="font-cal text-emphasis mt-2 text-4xl font-extrabold sm:text-5xl"> <h1 className="font-cal text-emphasis mt-2 text-4xl font-extrabold sm:text-5xl">
{isSuccessPage {isSuccessPage ? "Booking not found" : t("page_doesnt_exist")}
? t("booking_not_found")
: isInvalidToken
? t("invalid_verification_link")
: t("page_doesnt_exist")}
</h1> </h1>
{isSubpage ? ( {isSubpage && currentPageType !== pageType.TEAM ? (
<span className="mt-2 inline-block text-lg "> <span className="mt-2 inline-block text-lg ">
{t("check_spelling_mistakes_or_go_back")} {t("check_spelling_mistakes_or_go_back")}
</span> </span>
) : isInvalidToken ? (
<span className="mt-2 inline-block text-lg">{t("token_invalid_expired")}</span>
) : isCalcom ? ( ) : isCalcom ? (
<a target="_blank" href={url} className="mt-2 inline-block text-lg" rel="noreferrer"> <a target="_blank" href={url} className="mt-2 inline-block text-lg" rel="noreferrer">
{t("the_username")}{" "} {t(`404_the_${currentPageType.toLowerCase()}`)}{" "}
<strong className="text-blue-500"> <strong className="text-blue-500">
{new URL(WEBSITE_URL).hostname} {new URL(WEBSITE_URL).hostname}
{username} {username}
@@ -227,18 +253,17 @@ export default function Custom404() {
</a> </a>
) : ( ) : (
<span className="mt-2 inline-block text-lg"> <span className="mt-2 inline-block text-lg">
{t("the_username")}{" "} {t(`404_the_${currentPageType.toLowerCase()}`)}{" "}
<strong className="text-lgtext-green-500 mt-2 inline-block">{username}</strong>{" "} <strong className="text-lgtext-green-500 mt-2 inline-block">{username}</strong>{" "}
{t("is_still_available")} {t("is_still_available")}
</span> </span>
)} )}
</div> </div>
<div className="mt-12"> <div className="mt-12">
<h2 className="text-subtle text-sm font-semibold uppercase tracking-wide"> {((!isSubpage && isCalcom) ||
{t("popular_pages")} currentPageType === pageType.ORG ||
</h2> currentPageType === pageType.TEAM) && (
{!isSubpage && isCalcom && ( <ul role="list" className="my-4">
<ul role="list" className="mt-4">
<li className="border-2 border-green-500 px-4 py-2"> <li className="border-2 border-green-500 px-4 py-2">
<a <a
href={url} href={url}
@@ -255,11 +280,20 @@ export default function Custom404() {
<span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 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">{`${
currentPageType === pageType.TEAM
? `${new URL(WEBSITE_URL).host}/team/`
: ""
}${username}${
currentPageType === pageType.ORG ? `.${subdomainSuffix()}` : ""
}`}</strong>
</span> </span>
</span> </span>
</h3> </h3>
<p className="text-subtle text-base">{t("claim_username_and_schedule_events")}</p> <p className="text-subtle text-base">
{t(`404_claim_entity_${currentPageType.toLowerCase()}`)}
</p>
</div> </div>
<div className="flex-shrink-0 self-center"> <div className="flex-shrink-0 self-center">
<ChevronRight className="text-muted h-5 w-5" aria-hidden="true" /> <ChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
@@ -268,33 +302,37 @@ export default function Custom404() {
</li> </li>
</ul> </ul>
)} )}
<h2 className="text-subtle text-sm font-semibold uppercase tracking-wide">
<ul role="list" className="border-subtle divide-subtle mt-4 divide-y"> {t("popular_pages")}
{links.map((link, linkIdx) => ( </h2>
<li key={linkIdx} className="px-4 py-2"> <ul role="list" className="border-subtle divide-subtle divide-y">
<Link {links
href={link.href} .filter((_, idx) => currentPageType === pageType.ORG || idx !== 0)
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse"> .map((link, linkIdx) => (
<div className="flex-shrink-0"> <li key={linkIdx} className="px-4 py-2">
<span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg"> <Link
<link.icon className="text-default h-6 w-6" aria-hidden="true" /> href={link.href}
</span> className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
</div> <div className="flex-shrink-0">
<div className="min-w-0 flex-1"> <span className="bg-muted flex h-12 w-12 items-center justify-center rounded-lg">
<h3 className="text-emphasis text-base font-medium"> <link.icon className="text-default h-6 w-6" aria-hidden="true" />
<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" />
{link.title}
</span> </span>
</h3> </div>
<p className="text-subtle text-base">{link.description}</p> <div className="min-w-0 flex-1">
</div> <h3 className="text-emphasis text-base font-medium">
<div className="flex-shrink-0 self-center"> <span className="focus-within:ring-empthasis rounded-sm focus-within:ring-2 focus-within:ring-offset-2">
<ChevronRight className="text-muted h-5 w-5" aria-hidden="true" /> <span className="absolute inset-0" aria-hidden="true" />
</div> {link.title}
</Link> </span>
</li> </h3>
))} <p className="text-subtle text-base">{link.description}</p>
</div>
<div className="flex-shrink-0 self-center">
<ChevronRight className="text-muted h-5 w-5" aria-hidden="true" />
</div>
</Link>
</li>
))}
<li className="px-4 py-2"> <li className="px-4 py-2">
<a <a
href={JOIN_SLACK} href={JOIN_SLACK}
+1 -1
View File
@@ -21,7 +21,7 @@ export default function Error500() {
<div className="rtl: bg-default m-auto rounded-md 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-emphasis text-6xl">500</h1> <h1 className="font-cal text-emphasis text-6xl">500</h1>
<h2 className="text-emphasis mt-6 text-2xl font-medium">It&apos;s not you, it&apos;s us.</h2> <h2 className="text-emphasis mt-6 text-2xl font-medium">It&apos;s not you, it&apos;s us.</h2>
<p className="text-default mt-4 mb-6 max-w-2xl text-sm"> <p className="text-default mb-6 mt-4 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>
+9 -4
View File
@@ -37,7 +37,8 @@ import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr"; import { ssrInit } from "@server/lib/ssr";
export default function User(props: inferSSRProps<typeof getServerSideProps> & EmbedProps) { export type UserPageProps = inferSSRProps<typeof getServerSideProps> & EmbedProps;
export function UserPage(props: UserPageProps) {
const { const {
users, users,
profile, profile,
@@ -102,6 +103,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const query = { ...router.query }; const query = { ...router.query };
delete query.user; // So it doesn't display in the Link (and make tests fail) delete query.user; // So it doesn't display in the Link (and make tests fail)
delete query.orgSlug;
const nameOrUsername = user.name || user.username || ""; const nameOrUsername = user.name || user.username || "";
/* /*
@@ -132,7 +134,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
className={classNames( className={classNames(
shouldAlignCentrally ? "mx-auto" : "", shouldAlignCentrally ? "mx-auto" : "",
isEmbed ? "border-booker border-booker-width bg-default rounded-md border" : "", isEmbed ? "border-booker border-booker-width bg-default rounded-md border" : "",
"max-w-3xl py-24 px-4" "max-w-3xl px-4 py-24"
)}> )}>
{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">
@@ -207,8 +209,8 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
); );
} }
User.isBookingPage = true; UserPage.isBookingPage = true;
User.PageWrapper = PageWrapper; UserPage.PageWrapper = PageWrapper;
const getEventTypesWithHiddenFromDB = async (userId: number) => { const getEventTypesWithHiddenFromDB = async (userId: number) => {
return ( return (
@@ -360,6 +362,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const safeBio = markdownToSafeHTML(user.bio) || ""; const safeBio = markdownToSafeHTML(user.bio) || "";
const markdownStrippedBio = stripMarkdown(user?.bio || ""); const markdownStrippedBio = stripMarkdown(user?.bio || "");
return { return {
props: { props: {
users, users,
@@ -385,3 +388,5 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
}, },
}; };
}; };
export default UserPage;
+2 -2
View File
@@ -19,11 +19,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}); });
if (!foundToken) { if (!foundToken) {
return res.redirect(`${WEBAPP_URL}/404`); return res.status(401).json({ message: "No token found" });
} }
if (dayjs(foundToken?.expires).isBefore(dayjs())) { if (dayjs(foundToken?.expires).isBefore(dayjs())) {
return res.redirect(`${WEBAPP_URL}/404`); return res.status(401).json({ message: "Token expired" });
} }
const user = await prisma.user.update({ const user = await prisma.user.update({
+2 -1
View File
@@ -1,6 +1,7 @@
import type { GetStaticPropsContext } from "next"; import type { GetStaticPropsContext } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import type { ReactElement } from "react";
import z from "zod"; import z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -21,7 +22,7 @@ export default function Error() {
const router = useRouter(); const router = useRouter();
const { error } = querySchema.parse(router.query); const { error } = querySchema.parse(router.query);
const isTokenVerificationError = error?.toLowerCase() === "verification"; const isTokenVerificationError = error?.toLowerCase() === "verification";
let errorMsg = <SkeletonText />; let errorMsg: string | ReactElement = <SkeletonText />;
if (router.isReady) { if (router.isReady) {
errorMsg = isTokenVerificationError ? t("token_invalid_expired") : t("error_during_login"); errorMsg = isTokenVerificationError ? t("token_invalid_expired") : t("error_during_login");
} }
+1 -1
View File
@@ -254,7 +254,7 @@ export default function Availability() {
</ConfirmationDialogContent> </ConfirmationDialogContent>
</Dialog> </Dialog>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<div className="flex h-9 flex-row items-center justify-between py-2 px-4 hover:bg-gray-100"> <div className="flex h-9 flex-row items-center justify-between px-4 py-2 hover:bg-gray-100">
<Skeleton <Skeleton
as={Label} as={Label}
htmlFor="hiddenSwitch" htmlFor="hiddenSwitch"
+17
View File
@@ -1,4 +1,5 @@
import { useAutoAnimate } from "@formkit/auto-animate/react"; import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useRouter } from "next/router";
import { NewScheduleButton, ScheduleListItem } from "@calcom/features/schedules"; import { NewScheduleButton, ScheduleListItem } from "@calcom/features/schedules";
import Shell from "@calcom/features/shell/Shell"; import Shell from "@calcom/features/shell/Shell";
@@ -20,6 +21,8 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
const meQuery = trpc.viewer.me.useQuery(); const meQuery = trpc.viewer.me.useQuery();
const router = useRouter();
const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({ const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({
onMutate: async ({ scheduleId }) => { onMutate: async ({ scheduleId }) => {
await utils.viewer.availability.list.cancel(); await utils.viewer.availability.list.cancel();
@@ -67,6 +70,19 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
}, },
}); });
const duplicateMutation = trpc.viewer.availability.schedule.duplicate.useMutation({
onSuccess: async ({ schedule }) => {
await router.push(`/availability/${schedule.id}`);
showToast(t("schedule_created_successfully", { scheduleName: schedule.name }), "success");
},
onError: (err) => {
if (err instanceof HttpError) {
const message = `${err.statusCode}: ${err.message}`;
showToast(message, "error");
}
},
});
// Adds smooth delete button - item fades and old item slides into place // Adds smooth delete button - item fades and old item slides into place
const [animationParentRef] = useAutoAnimate<HTMLUListElement>(); const [animationParentRef] = useAutoAnimate<HTMLUListElement>();
@@ -96,6 +112,7 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
isDeletable={schedules.length !== 1} isDeletable={schedules.length !== 1}
updateDefault={updateMutation.mutate} updateDefault={updateMutation.mutate}
deleteFunction={deleteMutation.mutate} deleteFunction={deleteMutation.mutate}
duplicateFunction={duplicateMutation.mutate}
/> />
))} ))}
</ul> </ul>
+33 -8
View File
@@ -49,8 +49,9 @@ import type { Prisma } from "@calcom/prisma/client";
import { BookingStatus } from "@calcom/prisma/enums"; import { BookingStatus } from "@calcom/prisma/enums";
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils"; import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { Button, EmailInput, HeadSeo, Badge, useCalcomTheme } from "@calcom/ui"; import { Button, EmailInput, HeadSeo, Badge, useCalcomTheme, Alert } from "@calcom/ui";
import { X, ExternalLink, ChevronLeft, Check, Calendar } from "@calcom/ui/components/icon"; import { X, ExternalLink, ChevronLeft, Check, Calendar } from "@calcom/ui/components/icon";
import { AlertCircle } from "@calcom/ui/components/icon";
import { timeZone } from "@lib/clock"; import { timeZone } from "@lib/clock";
import type { inferSSRProps } from "@lib/types/inferSSRProps"; import type { inferSSRProps } from "@lib/types/inferSSRProps";
@@ -127,6 +128,10 @@ export default function Success(props: SuccessProps) {
? props?.bookingInfo?.attendees?.[0]?.name ? props?.bookingInfo?.attendees?.[0]?.name
: "Nameless"; : "Nameless";
const attendees = props?.bookingInfo?.attendees;
const isGmail = !!attendees.find((attendee) => attendee.email.includes("gmail.com"));
const [is24h, setIs24h] = useState(isBrowserLocale24h()); const [is24h, setIs24h] = useState(isBrowserLocale24h());
const { data: session } = useSession(); const { data: session } = useSession();
@@ -306,7 +311,7 @@ export default function Success(props: SuccessProps) {
/> />
)} )}
{userIsOwner && !isEmbed && ( {userIsOwner && !isEmbed && (
<div className="mt-2 ml-4 -mb-4"> <div className="-mb-4 ml-4 mt-2">
<Link <Link
href={allRemainingBookings ? "/bookings/recurring" : "/bookings/upcoming"} href={allRemainingBookings ? "/bookings/recurring" : "/bookings/upcoming"}
className="hover:bg-subtle text-subtle hover:text-default mt-2 inline-flex px-1 py-2 text-sm dark:hover:bg-transparent"> className="hover:bg-subtle text-subtle hover:text-default mt-2 inline-flex px-1 py-2 text-sm dark:hover:bg-transparent">
@@ -321,7 +326,7 @@ export default function Success(props: SuccessProps) {
<div <div
className={classNames( className={classNames(
shouldAlignCentrally ? "text-center" : "", shouldAlignCentrally ? "text-center" : "",
"flex items-end justify-center px-4 pt-4 pb-20 sm:block sm:p-0" "flex items-end justify-center px-4 pb-20 pt-4 sm:block sm:p-0"
)}> )}>
<div <div
className={classNames("my-4 transition-opacity sm:my-0", isEmbed ? "" : " inset-0")} className={classNames("my-4 transition-opacity sm:my-0", isEmbed ? "" : " inset-0")}
@@ -330,7 +335,7 @@ export default function Success(props: SuccessProps) {
className={classNames( className={classNames(
"main inline-block transform overflow-hidden rounded-lg border sm:my-8 sm:max-w-xl", "main inline-block transform overflow-hidden rounded-lg border sm:my-8 sm:max-w-xl",
!isBackgroundTransparent && " bg-default dark:bg-muted border-booker border-booker-width", !isBackgroundTransparent && " bg-default dark:bg-muted border-booker border-booker-width",
"px-8 pt-5 pb-4 text-left align-bottom transition-all sm:w-full sm:py-8 sm:align-middle" "px-8 pb-4 pt-5 text-left align-bottom transition-all sm:w-full sm:py-8 sm:align-middle"
)} )}
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
@@ -356,7 +361,7 @@ export default function Success(props: SuccessProps) {
{needsConfirmation && !isCancelled && <Calendar className="text-emphasis h-5 w-5" />} {needsConfirmation && !isCancelled && <Calendar className="text-emphasis h-5 w-5" />}
{isCancelled && <X className="h-5 w-5 text-red-600" />} {isCancelled && <X className="h-5 w-5 text-red-600" />}
</div> </div>
<div className="mt-6 mb-8 text-center last:mb-0"> <div className="mb-8 mt-6 text-center last:mb-0">
<h3 <h3
className="text-emphasis text-2xl font-semibold leading-6" className="text-emphasis text-2xl font-semibold leading-6"
data-testid={isCancelled ? "cancelled-headline" : ""} data-testid={isCancelled ? "cancelled-headline" : ""}
@@ -615,7 +620,7 @@ export default function Success(props: SuccessProps) {
className="border-subtle text-default mx-2 h-10 w-10 rounded-sm border px-3 py-2" className="border-subtle text-default mx-2 h-10 w-10 rounded-sm border px-3 py-2"
target="_blank"> target="_blank">
<svg <svg
className="mr-1 -mt-1.5 inline-block h-4 w-4" className="-mt-1.5 mr-1 inline-block h-4 w-4"
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"> viewBox="0 0 24 24">
@@ -642,7 +647,7 @@ export default function Success(props: SuccessProps) {
className="text-default border-subtle mx-2 h-10 w-10 rounded-sm border px-3 py-2" className="text-default border-subtle mx-2 h-10 w-10 rounded-sm border px-3 py-2"
target="_blank"> target="_blank">
<svg <svg
className="mr-1 -mt-1.5 inline-block h-4 w-4" className="-mt-1.5 mr-1 inline-block h-4 w-4"
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"> viewBox="0 0 24 24">
@@ -659,7 +664,7 @@ export default function Success(props: SuccessProps) {
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 1000" viewBox="0 0 1000 1000"
className="mr-1 -mt-1.5 inline-block h-4 w-4"> className="-mt-1.5 mr-1 inline-block h-4 w-4">
<title>{t("other")}</title> <title>{t("other")}</title>
<path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" /> <path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" />
</svg> </svg>
@@ -705,6 +710,26 @@ export default function Success(props: SuccessProps) {
</> </>
)} )}
</div> </div>
{isGmail && (
<Alert
className="main -mb-20 mt-4 inline-block text-left sm:-mt-4 sm:mb-4 sm:w-full sm:max-w-xl sm:align-middle"
severity="warning"
message={
<div>
<p className="font-semibold">{t("google_new_spam_policy")}</p>
<span className="underline">
<a
target="_blank"
href="https://cal.com/blog/google-s-new-spam-policy-may-be-affecting-your-invitations">
{t("resolve")}
</a>
</span>
</div>
}
CustomIcon={AlertCircle}
customIconColor="text-attention dark:text-orange-200"
/>
)}
</div> </div>
</div> </div>
</div> </div>
+3 -7
View File
@@ -168,18 +168,14 @@ const EventTypePage = (props: EventTypeSetupProps) => {
} }
if (err.data?.code === "UNAUTHORIZED") { if (err.data?.code === "UNAUTHORIZED") {
message = `${err.data.code}: You are not able to update this event`; message = `${err.data.code}: ${t("error_event_type_unauthorized_update")}`;
} }
if (err.data?.code === "PARSE_ERROR" || err.data?.code === "BAD_REQUEST") { if (err.data?.code === "PARSE_ERROR" || err.data?.code === "BAD_REQUEST") {
message = `${err.data.code}: ${err.message}`; message = `${err.data.code}: ${t(err.message)}`;
} }
if (message) { showToast(message ? t(message) : t(err.message), "error");
showToast(message, "error");
} else {
showToast(err.message, "error");
}
}, },
}); });
+10 -10
View File
@@ -383,7 +383,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
<div className="group flex w-full max-w-full items-center justify-between overflow-hidden px-4 py-4 sm:px-6"> <div className="group flex w-full max-w-full items-center justify-between overflow-hidden px-4 py-4 sm:px-6">
{!(firstItem && firstItem.id === type.id) && ( {!(firstItem && firstItem.id === type.id) && (
<button <button
className="bg-default text-muted hover:text-emphasis border-default hover:border-emphasis invisible absolute left-[5px] -mt-4 mb-4 -ml-4 hidden h-6 w-6 scale-0 items-center justify-center rounded-md border p-1 transition-all group-hover:visible group-hover:scale-100 sm:ml-0 sm:flex lg:left-[36px]" className="bg-default text-muted hover:text-emphasis border-default hover:border-emphasis invisible absolute left-[5px] -ml-4 -mt-4 mb-4 hidden h-6 w-6 scale-0 items-center justify-center rounded-md border p-1 transition-all group-hover:visible group-hover:scale-100 sm:ml-0 sm:flex lg:left-[36px]"
onClick={() => moveEventType(index, -1)}> onClick={() => moveEventType(index, -1)}>
<ArrowUp className="h-5 w-5" /> <ArrowUp className="h-5 w-5" />
</button> </button>
@@ -391,7 +391,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
{!(lastItem && lastItem.id === type.id) && ( {!(lastItem && lastItem.id === type.id) && (
<button <button
className="bg-default text-muted border-default hover:text-emphasis hover:border-emphasis invisible absolute left-[5px] mt-8 -ml-4 hidden h-6 w-6 scale-0 items-center justify-center rounded-md border p-1 transition-all group-hover:visible group-hover:scale-100 sm:ml-0 sm:flex lg:left-[36px]" className="bg-default text-muted border-default hover:text-emphasis hover:border-emphasis invisible absolute left-[5px] -ml-4 mt-8 hidden h-6 w-6 scale-0 items-center justify-center rounded-md border p-1 transition-all group-hover:visible group-hover:scale-100 sm:ml-0 sm:flex lg:left-[36px]"
onClick={() => moveEventType(index, 1)}> onClick={() => moveEventType(index, 1)}>
<ArrowDown className="h-5 w-5" /> <ArrowDown className="h-5 w-5" />
</button> </button>
@@ -401,7 +401,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
<div className="flex justify-between space-x-2 rtl:space-x-reverse"> <div className="flex justify-between space-x-2 rtl:space-x-reverse">
{type.team && !isManagedEventType && ( {type.team && !isManagedEventType && (
<AvatarGroup <AvatarGroup
className="relative top-1 right-3" className="relative right-3 top-1"
size="sm" size="sm"
truncateAfter={4} truncateAfter={4}
items={type.users.map( items={type.users.map(
@@ -415,12 +415,12 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
)} )}
{isManagedEventType && ( {isManagedEventType && (
<AvatarGroup <AvatarGroup
className="relative top-1 right-3" className="relative right-3 top-1"
size="sm" size="sm"
truncateAfter={4} truncateAfter={4}
items={type.children items={type.children
.flatMap((ch) => ch.users) .flatMap((ch) => ch.users)
.map((user: User) => ({ .map((user: Pick<User, "name" | "username">) => ({
alt: user.name || "", alt: user.name || "",
image: `${WEBAPP_URL}/${user.username}/avatar.png`, image: `${WEBAPP_URL}/${user.username}/avatar.png`,
title: user.name || "", title: user.name || "",
@@ -640,7 +640,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
)} )}
<DropdownMenuSeparator /> <DropdownMenuSeparator />
{!isManagedEventType && ( {!isManagedEventType && (
<div className="hover:bg-subtle flex h-9 cursor-pointer flex-row items-center justify-between py-2 px-4"> <div className="hover:bg-subtle flex h-9 cursor-pointer flex-row items-center justify-between px-4 py-2">
<Skeleton <Skeleton
as={Label} as={Label}
htmlFor="hiddenSwitch" htmlFor="hiddenSwitch"
@@ -728,10 +728,10 @@ const EventTypeListHeading = ({
{profile?.name || ""} {profile?.name || ""}
</Link> </Link>
{membershipCount && teamId && ( {membershipCount && teamId && (
<span className="text-subtle ms-2 me-2 relative -top-px text-xs"> <span className="text-subtle relative -top-px me-2 ms-2 text-xs">
<Link href={`/settings/teams/${teamId}/members`}> <Link href={`/settings/teams/${teamId}/members`}>
<Badge variant="gray"> <Badge variant="gray">
<Users className="mr-1 -mt-px inline h-3 w-3" /> <Users className="-mt-px mr-1 inline h-3 w-3" />
{membershipCount} {membershipCount}
</Badge> </Badge>
</Link> </Link>
@@ -747,7 +747,7 @@ const EventTypeListHeading = ({
</div> </div>
{!profile?.slug && !!teamId && ( {!profile?.slug && !!teamId && (
<button onClick={() => publishTeamMutation.mutate({ teamId })}> <button onClick={() => publishTeamMutation.mutate({ teamId })}>
<Badge variant="gray" className="mb-1 -ml-2"> <Badge variant="gray" className="-ml-2 mb-1">
{t("upgrade")} {t("upgrade")}
</Badge> </Badge>
</button> </button>
@@ -861,7 +861,7 @@ const EventTypesPage = () => {
const filters = getTeamsFiltersFromQuery(router.query); const filters = getTeamsFiltersFromQuery(router.query);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer as any, { filters }); const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer as any, filters && { filters });
return ( return (
<div> <div>
+1 -1
View File
@@ -77,7 +77,7 @@ export default function InsightsPage() {
<></> <></>
) : ( ) : (
<FiltersProvider> <FiltersProvider>
<div className="mb-8 mt-0 ml-auto flex w-full flex-wrap justify-between md:-mt-8"> <div className="mb-8 ml-auto mt-0 flex w-full flex-wrap justify-between md:-mt-8">
<Heading /> <Heading />
<Filters /> <Filters />
</div> </div>
+1 -1
View File
@@ -19,7 +19,7 @@ export default function MaintenancePage() {
</Head> </Head>
<div className="bg-default m-auto rounded-md p-10 text-right ltr:text-left"> <div className="bg-default m-auto rounded-md p-10 text-right ltr:text-left">
<h1 className="text-emphasis text-2xl font-medium">{t("under_maintenance")}</h1> <h1 className="text-emphasis text-2xl font-medium">{t("under_maintenance")}</h1>
<p className="text-default mt-4 mb-6 max-w-2xl text-sm"> <p className="text-default mb-6 mt-4 max-w-2xl text-sm">
{t("under_maintenance_description", { appName: APP_NAME })} {t("under_maintenance_description", { appName: APP_NAME })}
</p> </p>
<Button href={`${WEBSITE_URL}/support`}>{t("contact_support")}</Button> <Button href={`${WEBSITE_URL}/support`}>{t("contact_support")}</Button>
+13 -2
View File
@@ -14,7 +14,7 @@ import PageWrapper from "@components/PageWrapper";
type PageProps = inferSSRProps<typeof getServerSideProps>; type PageProps = inferSSRProps<typeof getServerSideProps>;
export default function Type({ slug, user, booking, away, isBrandingHidden }: PageProps) { export default function Type({ slug, user, booking, away, isBrandingHidden, isTeamEvent }: PageProps) {
return ( return (
<main className="flex h-full min-h-[100dvh] items-center justify-center"> <main className="flex h-full min-h-[100dvh] items-center justify-center">
<BookerSeo <BookerSeo
@@ -29,6 +29,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa
rescheduleBooking={booking} rescheduleBooking={booking}
isAway={away} isAway={away}
hideBranding={isBrandingHidden} hideBranding={isBrandingHidden}
isTeamEvent={isTeamEvent}
/> />
</main> </main>
); );
@@ -57,6 +58,11 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
username: true, username: true,
}, },
}, },
team: {
select: {
id: true,
},
},
}, },
}, },
}, },
@@ -96,9 +102,11 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
booking = await getBookingByUidOrRescheduleUid(`${rescheduleUid}`); booking = await getBookingByUidOrRescheduleUid(`${rescheduleUid}`);
} }
const isTeamEvent = !!hashedLink.eventType?.team?.id;
// We use this to both prefetch the query on the server, // We use this to both prefetch the query on the server,
// as well as to check if the event exist, so we c an show a 404 otherwise. // as well as to check if the event exist, so we c an show a 404 otherwise.
const eventData = await ssr.viewer.public.event.fetch({ username, eventSlug: slug }); const eventData = await ssr.viewer.public.event.fetch({ username, eventSlug: slug, isTeamEvent });
if (!eventData) { if (!eventData) {
return { return {
@@ -114,6 +122,9 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
slug, slug,
trpcState: ssr.dehydrate(), trpcState: ssr.dehydrate(),
isBrandingHidden: user?.hideBranding, isBrandingHidden: user?.hideBranding,
// Sending the team event from the server, because this template file
// is reused for both team and user events.
isTeamEvent,
}, },
}; };
} }
@@ -30,6 +30,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa
rescheduleBooking={booking} rescheduleBooking={booking}
isAway={away} isAway={away}
hideBranding={isBrandingHidden} hideBranding={isBrandingHidden}
isTeamEvent
/> />
</main> </main>
); );
@@ -71,7 +72,11 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
// We use this to both prefetch the query on the server, // We use this to both prefetch the query on the server,
// as well as to check if the event exist, so we c an show a 404 otherwise. // as well as to check if the event exist, so we c an show a 404 otherwise.
const eventData = await ssr.viewer.public.event.fetch({ username: teamSlug, eventSlug: meetingSlug }); const eventData = await ssr.viewer.public.event.fetch({
username: teamSlug,
eventSlug: meetingSlug,
isTeamEvent: true,
});
if (!eventData) { if (!eventData) {
return { return {
@@ -0,0 +1 @@
export { getServerSideProps, default } from "../../../[user]/[type]";
@@ -0,0 +1,40 @@
import type { GetServerSidePropsContext } from "next";
import prisma from "@calcom/prisma";
import PageWrapper from "@components/PageWrapper";
import type { UserPageProps } from "../../../[user]";
import UserPage, { getServerSideProps as GSSUserPage } from "../../../[user]";
import type { TeamPageProps } from "../../../team/[slug]";
import TeamPage, { getServerSideProps as GSSTeamPage } from "../../../team/[slug]";
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
const team = await prisma.team.findFirst({
where: {
slug: ctx.query.user as string,
parentId: {
not: null,
},
parent: {
slug: ctx.query.orgSlug as string,
},
},
select: {
id: true,
},
});
if (team) {
return GSSTeamPage({ ...ctx, query: { slug: ctx.query.user } });
}
return GSSUserPage({ ...ctx, query: { user: ctx.query.user } });
};
type Props = UserPageProps | TeamPageProps;
export default function Page(props: Props) {
if ((props as TeamPageProps)?.team) return TeamPage(props as TeamPageProps);
return UserPage(props as UserPageProps);
}
Page.PageWrapper = PageWrapper;
+1
View File
@@ -0,0 +1 @@
export { getServerSideProps, default } from "../../team/[slug]";
@@ -0,0 +1 @@
export { getServerSideProps, default } from "../../../../team/[slug]/[type]";
@@ -0,0 +1 @@
export { getServerSideProps, default } from "../../../../team/[slug]";
+1 -1
View File
@@ -25,7 +25,7 @@ const CtaRow = ({ title, description, className, children }: CtaRowProps) => {
<h2 className="font-medium">{title}</h2> <h2 className="font-medium">{title}</h2>
<p>{description}</p> <p>{description}</p>
</div> </div>
<div className="flex-shrink-0 pt-3 sm:ml-auto sm:pt-0 sm:pl-3">{children}</div> <div className="flex-shrink-0 pt-3 sm:ml-auto sm:pl-3 sm:pt-0">{children}</div>
</section> </section>
<hr className="border-subtle" /> <hr className="border-subtle" />
</> </>
@@ -57,7 +57,7 @@ const ApiKeysView = () => {
<div> <div>
{isLoading ? null : data?.length ? ( {isLoading ? null : data?.length ? (
<> <>
<div className="mt-6 mb-8 rounded-md border"> <div className="mb-8 mt-6 rounded-md border">
{data.map((apiKey, index) => ( {data.map((apiKey, index) => (
<ApiKeyListItem <ApiKeyListItem
key={apiKey.id} key={apiKey.id}
@@ -32,7 +32,7 @@ const SkeletonLoader = ({ title, description }: { title: string; description: st
return ( return (
<SkeletonContainer> <SkeletonContainer>
<Meta title={title} description={description} /> <Meta title={title} description={description} />
<div className="mt-6 mb-8 space-y-6"> <div className="mb-8 mt-6 space-y-6">
<div className="flex items-center"> <div className="flex items-center">
<SkeletonButton className="mr-6 h-32 w-48 rounded-md p-5" /> <SkeletonButton className="mr-6 h-32 w-48 rounded-md p-5" />
<SkeletonButton className="mr-6 h-32 w-48 rounded-md p-5" /> <SkeletonButton className="mr-6 h-32 w-48 rounded-md p-5" />
@@ -70,6 +70,13 @@ const AppearanceView = () => {
}, },
}); });
const selectedTheme = formMethods.watch("theme");
const selectedThemeIsDark =
selectedTheme === "dark" ||
(selectedTheme === "" &&
typeof document !== "undefined" &&
document.documentElement.classList.contains("dark"));
const { const {
formState: { isSubmitting, isDirty }, formState: { isSubmitting, isDirty },
reset, reset,
@@ -144,6 +151,7 @@ const AppearanceView = () => {
<hr className="border-subtle my-8 border [&:has(+hr)]:hidden" /> <hr className="border-subtle my-8 border [&:has(+hr)]:hidden" />
<BookerLayoutSelector <BookerLayoutSelector
isDark={selectedThemeIsDark}
name="metadata.defaultBookerLayouts" name="metadata.defaultBookerLayouts"
title={t("bookerlayout_user_settings_title")} title={t("bookerlayout_user_settings_title")}
description={t("bookerlayout_user_settings_description")} description={t("bookerlayout_user_settings_description")}
@@ -34,7 +34,7 @@ import PageWrapper from "@components/PageWrapper";
const SkeletonLoader = () => { const SkeletonLoader = () => {
return ( return (
<SkeletonContainer> <SkeletonContainer>
<div className="mt-6 mb-8 space-y-6"> <div className="mb-8 mt-6 space-y-6">
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
@@ -33,7 +33,7 @@ const SkeletonLoader = ({ title, description }: { title: string; description: st
return ( return (
<SkeletonContainer> <SkeletonContainer>
<Meta title={title} description={description} /> <Meta title={title} description={description} />
<div className="divide-subtle mt-6 mb-8 space-y-6"> <div className="divide-subtle mb-8 mt-6 space-y-6">
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
</div> </div>
@@ -29,7 +29,7 @@ const SkeletonLoader = ({ title, description }: { title: string; description: st
return ( return (
<SkeletonContainer> <SkeletonContainer>
<Meta title={title} description={description} /> <Meta title={title} description={description} />
<div className="mt-6 mb-8 space-y-6"> <div className="mb-8 mt-6 space-y-6">
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
@@ -48,7 +48,7 @@ const SkeletonLoader = ({ title, description }: { title: string; description: st
return ( return (
<SkeletonContainer> <SkeletonContainer>
<Meta title={title} description={description} /> <Meta title={title} description={description} />
<div className="mt-6 mb-8 space-y-6"> <div className="mb-8 mt-6 space-y-6">
<div className="flex items-center"> <div className="flex items-center">
<SkeletonAvatar className="me-4 h-16 w-16 px-4" /> <SkeletonAvatar className="me-4 h-16 w-16 px-4" />
<SkeletonButton className="h-6 w-32 rounded-md p-5" /> <SkeletonButton className="h-6 w-32 rounded-md p-5" />
@@ -12,7 +12,7 @@ import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
const SkeletonLoader = () => { const SkeletonLoader = () => {
return ( return (
<SkeletonContainer> <SkeletonContainer>
<div className="mt-6 mb-8 space-y-6"> <div className="mb-8 mt-6 space-y-6">
<div className="flex items-center"> <div className="flex items-center">
<SkeletonButton className="mr-6 h-8 w-20 rounded-md p-5" /> <SkeletonButton className="mr-6 h-8 w-20 rounded-md p-5" />
<SkeletonText className="h-8 w-full" /> <SkeletonText className="h-8 w-full" />
+2 -1
View File
@@ -29,6 +29,7 @@ import Team from "@components/team/screens/Team";
import { ssrInit } from "@server/lib/ssr"; import { ssrInit } from "@server/lib/ssr";
export type TeamPageProps = inferSSRProps<typeof getServerSideProps>; export type TeamPageProps = inferSSRProps<typeof getServerSideProps>;
function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain }: TeamPageProps) { function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain }: TeamPageProps) {
useTheme(team.theme); useTheme(team.theme);
const showMembers = useToggleQuery("members"); const showMembers = useToggleQuery("members");
@@ -170,7 +171,7 @@ function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain }
profile: { name: `${team.name}`, image: getPlaceholderAvatar(team.logo, team.name) }, profile: { name: `${team.name}`, image: getPlaceholderAvatar(team.logo, team.name) },
}} }}
/> />
<main className="dark:bg-darkgray-50 bg-subtle mx-auto max-w-3xl rounded-md px-4 pt-12 pb-12"> <main className="dark:bg-darkgray-50 bg-subtle mx-auto max-w-3xl rounded-md px-4 pb-12 pt-12">
<div className="mx-auto mb-8 max-w-3xl text-center"> <div className="mx-auto mb-8 max-w-3xl text-center">
<div className="relative"> <div className="relative">
<Avatar <Avatar
+1 -1
View File
@@ -205,7 +205,7 @@ export function VideoMeetingInfo(props: VideoMeetingInfo) {
<> <>
<aside <aside
className={classNames( className={classNames(
"no-scrollbar fixed top-0 left-0 z-30 flex h-full w-64 transform justify-between overflow-x-hidden overflow-y-scroll transition-all duration-300 ease-in-out", "no-scrollbar fixed left-0 top-0 z-30 flex h-full w-64 transform justify-between overflow-x-hidden overflow-y-scroll transition-all duration-300 ease-in-out",
open ? "translate-x-0" : "-translate-x-[232px]" open ? "translate-x-0" : "-translate-x-[232px]"
)}> )}>
<main className="prose-sm prose max-w-64 prose-a:text-white prose-h3:text-white prose-h3:font-cal scroll-bar scrollbar-track-w-20 w-full overflow-scroll overflow-x-hidden border-r border-gray-300/20 bg-black/80 p-4 text-white shadow-sm backdrop-blur-lg"> <main className="prose-sm prose max-w-64 prose-a:text-white prose-h3:text-white prose-h3:font-cal scroll-bar scrollbar-track-w-20 w-full overflow-scroll overflow-x-hidden border-r border-gray-300/20 bg-black/80 p-4 text-white shadow-sm backdrop-blur-lg">
+4 -4
View File
@@ -19,13 +19,13 @@ export default function MeetingUnavailable(props: inferSSRProps<typeof getServer
<HeadSeo title="Meeting Unavailable" description="Meeting Unavailable" /> <HeadSeo title="Meeting Unavailable" description="Meeting Unavailable" />
<main className="mx-auto my-24 max-w-3xl"> <main className="mx-auto my-24 max-w-3xl">
<div className="fixed inset-0 z-50 overflow-y-auto"> <div className="fixed inset-0 z-50 overflow-y-auto">
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0"> <div className="flex min-h-screen items-end justify-center px-4 pb-20 pt-4 text-center sm:block sm:p-0">
<div className="fixed inset-0 my-4 transition-opacity sm:my-0" aria-hidden="true"> <div className="fixed inset-0 my-4 transition-opacity sm:my-0" aria-hidden="true">
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true"> <span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
&#8203; &#8203;
</span> </span>
<div <div
className="bg-default inline-block transform overflow-hidden rounded-lg px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6 sm:align-middle" className="bg-default inline-block transform overflow-hidden rounded-lg px-4 pb-4 pt-5 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6 sm:align-middle"
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
aria-labelledby="modal-headline"> aria-labelledby="modal-headline">
@@ -38,12 +38,12 @@ export default function MeetingUnavailable(props: inferSSRProps<typeof getServer
This meeting is in the past. This meeting is in the past.
</h3> </h3>
</div> </div>
<div className="mt-4 border-t border-b py-4"> <div className="mt-4 border-b border-t py-4">
<h2 className="font-cal text-default mb-2 text-center text-lg font-medium"> <h2 className="font-cal text-default mb-2 text-center text-lg font-medium">
{props.booking.title} {props.booking.title}
</h2> </h2>
<p className="text-subtle text-center"> <p className="text-subtle text-center">
<Calendar className="mr-1 -mt-1 inline-block h-4 w-4" /> <Calendar className="-mt-1 mr-1 inline-block h-4 w-4" />
{dayjs(props.booking.startTime).format(detectBrowserTimeFormat + ", dddd DD MMMM YYYY")} {dayjs(props.booking.startTime).format(detectBrowserTimeFormat + ", dddd DD MMMM YYYY")}
</p> </p>
</div> </div>
@@ -23,7 +23,7 @@ export default function MeetingNotStarted(props: inferSSRProps<typeof getServerS
<> <>
<h2 className="mb-2 text-center font-medium">{props.booking.title}</h2> <h2 className="mb-2 text-center font-medium">{props.booking.title}</h2>
<p className="text-subtle text-center"> <p className="text-subtle text-center">
<Calendar className="mr-1 -mt-1 inline-block h-4 w-4" /> <Calendar className="-mt-1 mr-1 inline-block h-4 w-4" />
{dayjs(props.booking.startTime).format(detectBrowserTimeFormat + ", dddd DD MMMM YYYY")} {dayjs(props.booking.startTime).format(detectBrowserTimeFormat + ", dddd DD MMMM YYYY")}
</p> </p>
</> </>
@@ -0,0 +1,78 @@
<svg width="208" height="120" viewBox="0 0 208 120" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g clip-path="url(#clip0_5291_194335)">
<rect width="208" height="120" rx="6" fill="url(#paint0_radial_5291_194335)"/>
<rect x="25.4497" y="14.6206" width="157.101" height="90.7591" rx="5.35267" fill="#1A1A1A"/>
<circle cx="35.5909" cy="24.7618" r="2.67634" fill="#2B2B2B"/>
<rect x="40.0518" y="23.8696" width="14.2738" height="1.78422" rx="0.892112" fill="#2B2B2B"/>
<rect x="32.9146" y="31.0068" width="28.5476" height="2.67634" rx="0.892112" fill="#444444"/>
<rect x="32.9146" y="37.2515" width="21.4107" height="1.78422" rx="0.892112" fill="#2B2B2B"/>
<rect x="32.9146" y="42.604" width="21.4107" height="1.78422" rx="0.892112" fill="#2B2B2B"/>
<rect x="32.9146" y="47.957" width="21.4107" height="1.78422" rx="0.892112" fill="#2B2B2B"/>
<rect x="32.9146" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="40.0518" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="47.1885" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="54.3252" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="61.4619" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="68.5991" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="75.7363" y="58.6621" width="5.35267" height="1.78422" rx="0.892112" fill="#444444"/>
<rect x="47.1885" y="64.0146" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="54.3252" y="64.0146" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="61.4619" y="64.0146" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="68.5991" y="64.0146" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="75.7363" y="64.0146" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="32.9146" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="40.0518" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="47.1885" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="54.3252" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="61.4619" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="68.5991" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="75.7363" y="72.936" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="32.9146" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="40.0518" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="47.1885" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="54.3252" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="61.4619" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#575757"/>
<rect x="68.5991" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="75.7363" y="81.8569" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="32.9146" y="90.7783" width="5.35267" height="5.35267" rx="0.892112" fill="#1C1C1C"/>
<rect x="40.0518" y="90.7783" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="47.1885" y="90.7783" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="54.3252" y="90.7783" width="5.35267" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<path d="M89.1177 18.5171V101.484H90.9019V18.5171H89.1177Z" fill="#1C1C1C" mask="url(#path-3-inside-1_5291_194335)"/>
<rect x="96.5796" y="22.0854" width="21.4107" height="3.56845" rx="0.892112" fill="#444444"/>
<rect x="96.5796" y="29.2227" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="96.5796" y="38.1436" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="96.5796" y="47.0645" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="96.5796" y="55.9858" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="96.5796" y="64.9067" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="96.5796" y="73.8281" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="22.0854" width="21.4107" height="3.56845" rx="0.892112" fill="#444444"/>
<rect x="125.127" y="29.2227" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="38.1436" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="47.0649" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="55.9858" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="64.9067" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="125.127" y="73.8281" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="22.0854" width="21.4107" height="3.56845" rx="0.892112" fill="#444444"/>
<rect x="153.675" y="29.2227" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="38.1436" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="47.0645" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="55.9858" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="64.9067" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect x="153.675" y="73.8281" width="21.4107" height="5.35267" rx="0.892112" fill="#2B2B2B"/>
<rect opacity="0.2" x="0.666992" y="-1" width="208" height="120" fill="url(#pattern0)"/>
</g>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_5291_194335" transform="scale(0.00480769 0.00833333)"/>
</pattern>
<radialGradient id="paint0_radial_5291_194335" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(207.334 -1.47576e-05) rotate(145.398) scale(465.773 828.954)">
<stop stop-color="#282E39"/>
<stop offset="1" stop-color="#D4D4D5"/>
</radialGradient>
<clipPath id="clip0_5291_194335">
<rect width="208" height="120" rx="6" fill="white"/>
</clipPath>
<image id="image0_5291_194335" width="208" height="120" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANAAAAB4CAMAAAC0NYzFAAAAWlBMVEX////4+Pj4+Pj4+Pjw8PDw8PDo6Ojg4ODY2NjY2NjQ0NDIyMjAwMC4uLiwsLC4uLjIyMjIyMjU1NTY2Njc3Nzg4ODg4ODk5OTo6Ojo6Ojs7Ozs7Ozu7u709PT32s2WAAAAHnRSTlNISExKTFBQUFhQWGBgYGhoXFhYVFRUUlBPTk5QTEx67T/AAAAjPElEQVR4AUX6R6IjTW8Gaj7giXgRiUyymvr0yx3V/pfZ7jpM4Ifw4PdYhB95kiuLlTNl3v5s7wsXR1OL5IN+ckY4RfsefToFnPn9RXOVE2e6gOs9qsGjAPx4cbB+7HOGZXjx9KuzB/jBCdfjDVpD5mP4I9TvcLpCRvPKnwPOE9lAZ/qiOj0Ab5wrWGRTnEnqViknwYTAdiL41PXp8Mmet1ztAYHF5SQBXFWrhyhWuNPQ17Xz7tUc0OZxnEMd8OySy41KWN3Bt7C8d+GE9OVnZarLHiPiOjPqjpRInGLGtS9w0m/iRVt+f53kKo+KuszceTEbOeoJ+fPU/0G52ulaqxYSeiY9aN9db+MrCjScCvDvZGIa5GscCLwQp+DTme1pqHwcuX6ndBMsdwD22b6mrg8HL41r55nNvelE4LTR2So2PX0T3PkKLxjom9ly4PRjrbQThxosIv8+bJkOioucXui/TbOvryX13ZjMk6XR/G6LOqWuPm9h9jkGcbEdoGkmHO/LWt/LZ3pPsrztuUU+Bmt7LcDlPR9PXCoLLv+Pts873Dk4W08/Gm6wnBOMi8hfpvmU6Zy3zKFY6aXXkpepqWstHlc0CVcJtbsKhvZ0wKnRgyxPu2L9yAmmvHD58w68UmRvRj+lyy1gNWgsxbbHnT7H/vvXcFqHmu0hcXPz7ldGRl2P5YgHecGRLj5Zbk4rssvLQffjZb+ZzSt0y+HK08Ei4IXrJNWWqdOX7j/93/997c8RXdsBuAZkGpIFxkKmvk7dFF44ZI5ebJ7s/qdr6iJ0H3KFt4XWzTEHvHveF19HymI/m7Nh6YO2oi2db4gvVCypxqqeOnsE/tuYpr1+fuCJyhDpke/wsZiOdYHIja9X9+NUiHNvX/B+2oGTPsP9ULMpYUkTzt+/UKnMbq2Bws5y5wMRy3VBdA/kRizDHejVdStjp02n0oC+pQx6vriyUbcR2oVDL0BaHsJzedjFp/a1H7iOGbdw3YN98bb4SLm+HFvGj8HU3eqgPpUYz6CKXgXSdR4NA1cExPBMpItzGbnDRprbcYGM3mir5l8DlmUtPwiHBWsZ41H78fBtwNTtqNQXai1Oujk7X5Z3Oc8nTtA5+hC9mE2WkZ7ZQzM3C4GimVpQGccPJnN5OOwCZ2+VlcGjTgvjDAzJbSZ5Xy6v/VIsxiC2BQuvvUcn8rRTfbTODQTXnSEvJef3d0/ZXrWsjF7qZXcMU2G/K8LPcp3+PvvpN0YLgG23vohhpd1iep/Co/vBD5OmHWqK6gqpP1wugJjg3uIH2ftNrudMjavqlQcGBNvD7y9CL0hoK/vAnM/ZvISdxwxiw2Tj9NAsPd1q5s11Nte4Gy+FFGElaPuuTI4LOpwNGTuWYz/z7hUCYR53MQBi9ukJ2kighxpNh0yZ9kulLdLUfbzy9YprR2vaORnC7FtrLTJ7RuR//ufWPbvcDUwW7WM4Penibq5xJM6nsqc4t1fg2w0uhKMXIeFTB3nrO4M3VgvwFuj27L/7mF+jWM2cJ+ivWE23x1xblXH27c3bKHj10eeKF8rsSMXDkha2LTrmPLnC3qTNfidaHYk9NNSmndBPBs5MYB4/Cvxwdp2eR3rMhhf2s191nAQmTaf2wz6a1ZxUzmTesHJ74OrJQ3qf6+pPH+i4ppfv7Kg9/3LITIgoZ628cLZV51hLvXeVc/aCnj/nyPhSu5m9zLesTJ9aHd7bz+dpncXdBZl+OHsEPftcnMhXBtiDi5OiOx5PH/aj7nOabA0bAUbrvqvfqZuWxFyyb21YpqQGt/3hXWE2d/4PpjjmtPZSHIgVtjp9A9VY3nt5ZhrGbljy2FYRDTiOrgsJfX1suevN+PQ/0/SHOWkv1e86PqinnDL4wimo96bO769czOy4ihcv/Agw7q3p6TM1RecELpguR6gYhFdbVI3jBkaPB33VrTdX15IWg1Y31BuFR2UYQcUUdKhehohL5BSTYa/WuhHuHNLTfjztxbwBE4J36SOjy8K8I07GtcpqQNG9jxXYLnoJ9dnkj9GnBl5Z4NyfGtRT2jOFqa5hz+a11umHc1rqUPQgplsDn6tf+T9SGTQ97EdXYIN4x8OfATCO9ihw1zZ2Z0G+3W/mEI3mnVi8dmGm743Tp5u2lh0Gr8pyEZHqrLrYm9VV+KQONwme7icXFTjA5RPu9H6uJ/fZ8zRdsJkdbSld6ubQ5Jp9oGng7n/F9qTKsRjMNerQF0/VzAXHuVA3D5m+v081v3ykHwwXQsw5pN5F4Aqqe/Ub227IfeE9UA9M82Sf9hWj+xo7DpYWKzkMVDPlKV2dGofjemzSUkdNiCNQntlYf/8O7z1rmZHWxBfnl+CdGz9ce5pciOfpYVFV+7kixCo18MXPWrInFv2QXsBFBkc75zRps9Hg9aIZrtnHXsb2+5vdfyHtlpob2sdpV1yc0pze0aLnaAQdyDkGAek+R2zmkm2t7IG+6qIvbWgO4DCHaQHNlccp7m1cRvZf15QfdyZkOe9LAJkg6tH5K/Aj5qI9x40lN9KEOnD6JPNPx9tuJ3HGt0o9l7cCdx+HbD0WByf/npsH35pqVGiXFPuJamzPbNrjBshx33+3aDo3FYnuVnvG4wJje5HBwUmpuL+Hq3QeV6Qb2YiVaUPHLXIOK16R6a67pI0hr1yZHQ+Bfxd2ThfP07HYgAG89ht8TmNIA8oVe3Vn37Vx4LzZdFo7GD/Ycgbmec5DHc/24zlHPV/XpBcuj4KfGJbFdnF6j/6wMXla4Cqz2/No2vwzp0/3gxy4rvK+QMMDp8veLEXqXOEKt4zg5DpnhlCcUu1oZZ+AiutQxz1ZGimJUZU8D7RpZ9h+VLm0JbZl4tJPYZnmu0Uu38atZ0fvg/QIxe2TMg762AcDQ/twvKIHh1i27u+59wHKj1BnQF+aZRka2hwsemUGH4OGtbJdnu2hd9isT9Ww/DWe56PDeLuuPj45p84FBNc+Fp+kMo5aYI8Jv7/F1ZrrediBBaOumzviyXA4jbYEbq6+sdDvzQ0dXpgO3wM8Ncy4knGlxp7BLVwPh7+sUkLFh1OiRZ0o5lBWPYkPvBkOAS+d8C4TND49Xq9Axcy5Ls4wuGNQqi7s7SHIQv85gMcPubY0LmtZNHf31DnC2SY1x8U3JDwa5uQlwdDIU1o4lhNOCbxgUg3dTJw52j6h4xzhZXmRW1u5Cm0tkLwlxnkeRIsgh8sXdviiaW6vSL8WR7TKSguocLV9cW1GZogfA3Jf0vRyM3jqM+hzGaiDx2rOxQtv6VMegXNVN7UWM3Imp+lFvEThQQurUQdC15zZXprAHlhddRL57hgpdp2CxReXp3BlBLbVBcpuMNoQVDeEQwHXpSF3mdAWi2WoqWTYAAsvddHASczeIz8/P7+/p/Fnvlyg6JLKS64wmcl9GcvT75/HH6aO1mhMgyDmeyseLZ+HvLAavTFnk1fy+0swv7+xB5+GafED6hJD2YxjhR+rvpzRjMs4fqARN5O5DwZsw8qB2bXP2fPP//7vIgc/TgyewMHm2vPBwvYUi1K8pztPgAGW47jwrPVS1ad3aNOct8z/SbcHjjnZXAvOai+fWnSoyfbCvjhu47LNGFbUVJ1PJb767rk3dc7/QjokYN+8qjUDNxczKFCB4eC5HgnHz3JFvrzxAJRz8Obsi2+pFUtdmvnIjL9/FwFMa+xxh9lcDt3IG/pC0OyHLArsrjM1bQmCVX5/FzpCWKArG72i38y//3vKDGotOsi08YJrQK4rhn2GqekU+AGucpqrumZqX9pKLMt1/HjeA49MaP3fDVSYs8lVbnV7rqs5cz4WuvaME8SJXq3e04t9peai3dGsF2LxclF10fPnAWMu0GhzoZ8dbdkfvBZ+FsxV62+OybArFzOEB3oZXUsj1zOtLpxdTg5HTK5sHdhD80K66XoSGfs/qRfPDjVbDOBoaDFdHmYKNnGGqMsNmDeUk7eurmdYZ1g8xuPvN6XL2WMHh4qt2soMgHHd8s/NDtWei5rnngqvZXHFGXnZ+yFbPCb6P//T4Gwfw4iJHnjQbiN13WZ/vCyI3lNTh9yOFSxdeQjf3RCV6zCX+yQNHU0L2+LM4akHZzhJtuP0RX2Z4Mp+dnPP3nKQPa7KKzNw29x7JOVgpJZTMLn3F2/wzGYwhQ6al/G1Nhq0TyxO6PvE39bkFvZHGZG/f8GL/d09+3Lvu6tOoVGfkQNZdLvPVA/zRD1q7GfsBWnjAR7Tn4zjk+idpbl3o9+DoZPTafpSs/dhWLmYacD2o3Sq9suN9zPy/vsGJ6Ob319mzlD9PFCZZvpoU9cRM0Z/TR1hRcaD9GiDSxy+7eIwmS/BO2Ye+gTnWC7HOyJ9GXcIDTnP3m4ZVx854DRuzG7PGQqN6/57ZeJQ4Tv7xnmPI7G8NIJ5MErb4iqvvuQhlweYpAPFK1P5qv/z6g7MBpdvT2hAnt1q2ezQnp4qWDhyWQupz1YDQJu9tz3aj9lm/lpphfV/1li35yj3x4sxPTlZWPRsXqTAjDO80nt6GW0fhNi8G6JVsiQzpnm25Mm+YzlGXMPTbuopbC50x/KR4ICnHpcVWpxz9t3ZJNBcMve7i2WOo8A0mcebuuTOxkn8/j68izwcfKwCMMrVXkidd16wvOkD28kLoHQK9ui5Wg2LeJ/G8gKzy0trz749HZCl7Line truncated
</defs>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,67 @@
<svg width="208" height="120" viewBox="0 0 208 120" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g clip-path="url(#clip0_5291_194117)">
<rect width="208" height="120" rx="6" fill="url(#paint0_radial_5291_194117)"/>
<rect x="22" y="24" width="164" height="72" rx="6" fill="#1A1A1A"/>
<circle cx="33" cy="35" r="3" fill="#2B2B2B"/>
<rect x="38" y="34" width="16" height="2" rx="1" fill="#2B2B2B"/>
<rect x="30" y="42" width="24" height="3" rx="1" fill="#444444"/>
<rect x="30" y="49" width="24" height="2" rx="1" fill="#2B2B2B"/>
<rect x="30" y="55" width="24" height="2" rx="1" fill="#2B2B2B"/>
<rect x="30" y="61" width="24" height="2" rx="1" fill="#2B2B2B"/>
<rect x="30" y="67" width="24" height="2" rx="1" fill="#2B2B2B"/>
<path d="M61 28V92H63V28H61Z" fill="#1C1C1C" mask="url(#path-4-inside-1_5291_194117)"/>
<rect x="70" y="32" width="24" height="2" rx="1" fill="#2B2B2B"/>
<rect x="70" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="80" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="90" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="100" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="110" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="120" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="130" y="38" width="8" height="2" rx="1" fill="#444444"/>
<rect x="90" y="44" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="100" y="44" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="110" y="44" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="120" y="44" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="130" y="44" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="70" y="56" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="80" y="56" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="90" y="56" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="100" y="56" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="110" y="56" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="120" y="56" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="130" y="56" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="70" y="68" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="80" y="68" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="90" y="68" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="100" y="68" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="110" y="68" width="8" height="8" rx="1" fill="#575757"/>
<rect x="120" y="68" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="130" y="68" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="70" y="80" width="8" height="8" rx="1" fill="#1C1C1C"/>
<rect x="80" y="80" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="90" y="80" width="8" height="8" rx="1" fill="#2B2B2B"/>
<rect x="100" y="80" width="8" height="8" rx="1" fill="#2B2B2B"/>
<path d="M145 28V92H147V28H145Z" fill="#1C1C1C" mask="url(#path-13-inside-2_5291_194117)"/>
<rect x="154" y="32" width="24" height="2" rx="1" fill="#2B2B2B"/>
<rect x="154" y="38" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect x="154" y="47" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect x="154" y="56" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect x="154" y="65" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect x="154" y="74" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect x="154" y="83" width="24" height="5" rx="1" fill="#2B2B2B"/>
<rect opacity="0.2" width="208" height="120" fill="url(#pattern0)"/>
</g>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_5291_194117" transform="scale(0.00480769 0.00833333)"/>
</pattern>
<radialGradient id="paint0_radial_5291_194117" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(207.334 -1.47576e-05) rotate(145.398) scale(465.773 828.954)">
<stop stop-color="#282E39"/>
<stop offset="1" stop-color="#D4D4D5"/>
</radialGradient>
<clipPath id="clip0_5291_194117">
<rect width="208" height="120" rx="6" fill="white"/>
</clipPath>
<image id="image0_5291_194117" width="208" height="120" xlink:href="data:image/png;base64,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 truncated
</defs>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,149 @@
<svg width="208" height="120" viewBox="0 0 208 120" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g clip-path="url(#clip0_5291_194186)">
<rect width="208" height="120" rx="6" fill="url(#paint0_radial_5291_194186)"/>
<rect x="26.7329" y="13.4136" width="154.535" height="93.1733" rx="5.49505" fill="#1A1A1A"/>
<circle cx="37.1435" cy="23.8247" r="2.74752" fill="#2B2B2B"/>
<rect x="41.7227" y="22.9087" width="14.6535" height="1.83168" rx="0.915842" fill="#2B2B2B"/>
<rect x="34.396" y="30.2354" width="29.3069" height="2.74752" rx="0.915842" fill="#444444"/>
<rect x="34.396" y="36.6465" width="21.9802" height="1.83168" rx="0.915842" fill="#2B2B2B"/>
<rect x="34.396" y="42.1411" width="21.9802" height="1.83168" rx="0.915842" fill="#2B2B2B"/>
<rect x="34.396" y="47.6362" width="21.9802" height="1.83168" rx="0.915842" fill="#2B2B2B"/>
<rect x="34.396" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="41.7227" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="49.0493" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="56.3765" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="63.7031" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="71.0298" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="78.3564" y="58.6265" width="5.49505" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="49.0493" y="64.1216" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="56.3765" y="64.1216" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="63.7031" y="64.1216" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="71.0298" y="64.1216" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="78.3564" y="64.1216" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="34.396" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="41.7227" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="49.0493" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="56.3765" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="63.7031" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="71.0298" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="78.3564" y="73.2798" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="34.396" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="41.7227" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="49.0493" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="56.3765" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="63.7031" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#575757"/>
<rect x="71.0298" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="78.3564" y="82.4385" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="34.396" y="91.5967" width="5.49505" height="5.49505" rx="0.915842" fill="#1C1C1C"/>
<rect x="41.7227" y="91.5967" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="49.0493" y="91.5967" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<rect x="56.3765" y="91.5967" width="5.49505" height="5.49505" rx="0.915842" fill="#2B2B2B"/>
<path d="M92.0943 17.4136V102.587H93.926V17.4136H92.0943Z" fill="#1C1C1C" mask="url(#path-3-inside-1_5291_194186)"/>
<g clip-path="url(#clip1_5291_194186)">
<rect x="100.337" y="21.0771" width="10.9901" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="114.99" y="21.0771" width="10.9901" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="129.644" y="21.0771" width="10.9901" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="144.297" y="21.0771" width="10.9901" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="158.951" y="21.0771" width="10.9901" height="1.83168" rx="0.915842" fill="#444444"/>
<rect x="98.5059" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<path d="M98.5059 28.4039C98.5059 27.3923 99.3259 26.5723 100.338 26.5723H113.159V32.0673H98.5059V28.4039Z" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="113.159" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="127.812" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="142.466" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.466" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="157.12" y="26.5723" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<path d="M157.12 26.5723H169.941C170.953 26.5723 171.773 27.3923 171.773 28.4039V32.0673H157.12V26.5723Z" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="98.5054" y="32.0669" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="32.0669" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="32.0669" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="32.0669" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="32.0669" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="37.562" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="37.562" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="37.562" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="37.562" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="37.562" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="43.0571" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="43.0571" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="43.0571" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="43.0571" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="43.0571" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="48.5522" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="48.5522" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="48.5522" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="48.5522" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="48.5522" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="54.0474" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="54.0474" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="54.0474" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="54.0474" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="54.0474" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="59.5425" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="59.5425" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="59.5425" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="59.5425" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="59.5425" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="65.0371" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="65.0371" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="65.0371" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="65.0371" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="65.0371" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="70.5322" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="70.5322" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="70.5322" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="70.5322" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="70.5322" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="76.0273" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="76.0273" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="76.0273" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="76.0273" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="76.0273" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="81.5225" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="81.5225" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="81.5225" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="81.5225" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="81.5225" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="87.0176" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="87.0176" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="87.0176" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="87.0176" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="157.119" y="87.0176" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="98.5054" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<path d="M98.5054 92.5127H113.159V98.0077H100.337C99.3254 98.0077 98.5054 97.1877 98.5054 96.1761V92.5127Z" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="113.159" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="113.159" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="127.812" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="127.812" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="142.465" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<rect x="142.465" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="157.119" y="92.5127" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
<path d="M157.119 92.5127H171.773V96.1761C171.773 97.1877 170.953 98.0077 169.941 98.0077H157.119V92.5127Z" stroke="#2B2B2B" stroke-width="0.457921"/>
<rect x="98.5054" y="59.5425" width="14.6535" height="10.9901" stroke="#2B2B2B"/>
<rect opacity="0.6" x="127.813" y="75.2798" width="14.6535" height="11.9901" fill="#525252" stroke="#2B2B2B"/>
<rect opacity="0.6" x="157.12" y="59.7104" width="14.6535" height="26.4851" fill="#525252" stroke="#2B2B2B"/>
<rect opacity="0.6" x="99.1196" y="81.5229" width="13.6535" height="15.6726" fill="#525252" stroke="#2B2B2B"/>
<rect opacity="0.6" x="99.1196" y="26.7104" width="13.6535" height="10.4851" fill="#525252" stroke="#2B2B2B"/>
<rect opacity="0.6" x="142.466" y="43.0571" width="14.6535" height="2.74752" fill="#525252" stroke="#2B2B2B"/>
<rect x="113.159" y="26.5718" width="14.6535" height="5.49505" stroke="#2B2B2B"/>
</g>
<rect opacity="0.2" x="0.333008" y="-1" width="208" height="120" fill="url(#pattern0)"/>
</g>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_5291_194186" transform="scale(0.00480769 0.00833333)"/>
</pattern>
<radialGradient id="paint0_radial_5291_194186" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(207.334 -1.47576e-05) rotate(145.398) scale(465.773 828.954)">
<stop stop-color="#282E39"/>
<stop offset="1" stop-color="#D4D4D5"/>
</radialGradient>
<clipPath id="clip0_5291_194186">
<rect width="208" height="120" rx="6" fill="white"/>
</clipPath>
<clipPath id="clip1_5291_194186">
<rect width="84.2574" height="84.2574" fill="white" transform="translate(93.0103 17.4136)"/>
</clipPath>
<image id="image0_5291_194186" width="208" height="120" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANAAAAB4CAMAAAC0NYzFAAAAWlBMVEX////4+Pj4+Pj4+Pjw8PDw8PDo6Ojg4ODY2NjY2NjQ0NDIyMjAwMC4uLiwsLC4uLjIyMjIyMjU1NTY2Njc3Nzg4ODg4ODk5OTo6Ojo6Ojs7Ozs7Ozu7u709PT32s2WAAAAHnRSTlNISExKTFBQUFhQWGBgYGhoXFhYVFRUUlBPTk5QTEx67T/AAAAjPElEQVR4AUX6R6IjTW8Gaj7giXgRiUyymvr0yx3V/pfZ7jpM4Ifw4PdYhB95kiuLlTNl3v5s7wsXR1OL5IN+ckY4RfsefToFnPn9RXOVE2e6gOs9qsGjAPx4cbB+7HOGZXjx9KuzB/jBCdfjDVpD5mP4I9TvcLpCRvPKnwPOE9lAZ/qiOj0Ab5wrWGRTnEnqViknwYTAdiL41PXp8Mmet1ztAYHF5SQBXFWrhyhWuNPQ17Xz7tUc0OZxnEMd8OySy41KWN3Bt7C8d+GE9OVnZarLHiPiOjPqjpRInGLGtS9w0m/iRVt+f53kKo+KuszceTEbOeoJ+fPU/0G52ulaqxYSeiY9aN9db+MrCjScCvDvZGIa5GscCLwQp+DTme1pqHwcuX6ndBMsdwD22b6mrg8HL41r55nNvelE4LTR2So2PX0T3PkKLxjom9ly4PRjrbQThxosIv8+bJkOioucXui/TbOvryX13ZjMk6XR/G6LOqWuPm9h9jkGcbEdoGkmHO/LWt/LZ3pPsrztuUU+Bmt7LcDlPR9PXCoLLv+Pts873Dk4W08/Gm6wnBOMi8hfpvmU6Zy3zKFY6aXXkpepqWstHlc0CVcJtbsKhvZ0wKnRgyxPu2L9yAmmvHD58w68UmRvRj+lyy1gNWgsxbbHnT7H/vvXcFqHmu0hcXPz7ldGRl2P5YgHecGRLj5Zbk4rssvLQffjZb+ZzSt0y+HK08Ei4IXrJNWWqdOX7j/93/997c8RXdsBuAZkGpIFxkKmvk7dFF44ZI5ebJ7s/qdr6iJ0H3KFt4XWzTEHvHveF19HymI/m7Nh6YO2oi2db4gvVCypxqqeOnsE/tuYpr1+fuCJyhDpke/wsZiOdYHIja9X9+NUiHNvX/B+2oGTPsP9ULMpYUkTzt+/UKnMbq2Bws5y5wMRy3VBdA/kRizDHejVdStjp02n0oC+pQx6vriyUbcR2oVDL0BaHsJzedjFp/a1H7iOGbdw3YN98bb4SLm+HFvGj8HU3eqgPpUYz6CKXgXSdR4NA1cExPBMpItzGbnDRprbcYGM3mir5l8DlmUtPwiHBWsZ41H78fBtwNTtqNQXai1Oujk7X5Z3Oc8nTtA5+hC9mE2WkZ7ZQzM3C4GimVpQGccPJnN5OOwCZ2+VlcGjTgvjDAzJbSZ5Xy6v/VIsxiC2BQuvvUcn8rRTfbTODQTXnSEvJef3d0/ZXrWsjF7qZXcMU2G/K8LPcp3+PvvpN0YLgG23vohhpd1iep/Co/vBD5OmHWqK6gqpP1wugJjg3uIH2ftNrudMjavqlQcGBNvD7y9CL0hoK/vAnM/ZvISdxwxiw2Tj9NAsPd1q5s11Nte4Gy+FFGElaPuuTI4LOpwNGTuWYz/z7hUCYR53MQBi9ukJ2kighxpNh0yZ9kulLdLUfbzy9YprR2vaORnC7FtrLTJ7RuR//ufWPbvcDUwW7WM4Penibq5xJM6nsqc4t1fg2w0uhKMXIeFTB3nrO4M3VgvwFuj27L/7mF+jWM2cJ+ivWE23x1xblXH27c3bKHj10eeKF8rsSMXDkha2LTrmPLnC3qTNfidaHYk9NNSmndBPBs5MYB4/Cvxwdp2eR3rMhhf2s191nAQmTaf2wz6a1ZxUzmTesHJ74OrJQ3qf6+pPH+i4ppfv7Kg9/3LITIgoZ628cLZV51hLvXeVc/aCnj/nyPhSu5m9zLesTJ9aHd7bz+dpncXdBZl+OHsEPftcnMhXBtiDi5OiOx5PH/aj7nOabA0bAUbrvqvfqZuWxFyyb21YpqQGt/3hXWE2d/4PpjjmtPZSHIgVtjp9A9VY3nt5ZhrGbljy2FYRDTiOrgsJfX1suevN+PQ/0/SHOWkv1e86PqinnDL4wimo96bO769czOy4ihcv/Agw7q3p6TM1RecELpguR6gYhFdbVI3jBkaPB33VrTdX15IWg1Y31BuFR2UYQcUUdKhehohL5BSTYa/WuhHuHNLTfjztxbwBE4J36SOjy8K8I07GtcpqQNG9jxXYLnoJ9dnkj9GnBl5Z4NyfGtRT2jOFqa5hz+a11umHc1rqUPQgplsDn6tf+T9SGTQ97EdXYIN4x8OfATCO9ihw1zZ2Z0G+3W/mEI3mnVi8dmGm743Tp5u2lh0Gr8pyEZHqrLrYm9VV+KQONwme7icXFTjA5RPu9H6uJ/fZ8zRdsJkdbSld6ubQ5Jp9oGng7n/F9qTKsRjMNerQF0/VzAXHuVA3D5m+v081v3ykHwwXQsw5pN5F4Aqqe/Ub227IfeE9UA9M82Sf9hWj+xo7DpYWKzkMVDPlKV2dGofjemzSUkdNiCNQntlYf/8O7z1rmZHWxBfnl+CdGz9ce5pciOfpYVFV+7kixCo18MXPWrInFv2QXsBFBkc75zRps9Hg9aIZrtnHXsb2+5vdfyHtlpob2sdpV1yc0pze0aLnaAQdyDkGAek+R2zmkm2t7IG+6qIvbWgO4DCHaQHNlccp7m1cRvZf15QfdyZkOe9LAJkg6tH5K/Aj5qI9x40lN9KEOnD6JPNPx9tuJ3HGt0o9l7cCdx+HbD0WByf/npsH35pqVGiXFPuJamzPbNrjBshx33+3aDo3FYnuVnvG4wJje5HBwUmpuL+Hq3QeV6Qb2YiVaUPHLXIOK16R6a67pI0hr1yZHQ+Bfxd2ThfP07HYgAG89ht8TmNIA8oVe3Vn37Vx4LzZdFo7GD/Ycgbmec5DHc/24zlHPV/XpBcuj4KfGJbFdnF6j/6wMXla4Cqz2/No2vwzp0/3gxy4rvK+QMMDp8veLEXqXOEKt4zg5DpnhlCcUu1oZZ+AiutQxz1ZGimJUZU8D7RpZ9h+VLm0JbZl4tJPYZnmu0Uu38atZ0fvg/QIxe2TMg762AcDQ/twvKIHh1i27u+59wHKj1BnQF+aZRka2hwsemUGH4OGtbJdnu2hd9isT9Ww/DWe56PDeLuuPj45p84FBNc+Fp+kMo5aYI8Jv7/F1ZrrediBBaOumzviyXA4jbYEbq6+sdDvzQ0dXpgO3wM8Ncy4knGlxp7BLVwPh7+sUkLFh1OiRZ0o5lBWPYkPvBkOAS+d8C4TND49Xq9Axcy5Ls4wuGNQqi7s7SHIQv85gMcPubY0LmtZNHf31DnC2SY1x8U3JDwa5uQlwdDIU1o4lhNOCbxgUg3dTJw52j6h4xzhZXmRW1u5Cm0tkLwlxnkeRIsgh8sXdviiaW6vSL8WR7TKSguocLV9cW1GZogfA3Jf0vRyM3jqM+hzGaiDx2rOxQtv6VMegXNVN7UWM3Imp+lFvEThQQurUQdC15zZXprAHlhddRL57hgpdp2CxReXp3BlBLbVBcpuMNoQVDeEQwHXpSF3mdAWi2WoqWTYAAsvddHASczeIz8/P7+/p/Fnvlyg6JLKS64wmcl9GcvT75/HH6aO1mhMgyDmeyseLZ+HvLAavTFnk1fy+0swv7+xB5+GafED6hJD2YxjhR+rvpzRjMs4fqARN5O5DwZsw8qB2bXP2fPP//7vIgc/TgyewMHm2vPBwvYUi1K8pztPgAGW47jwrPVS1ad3aNOct8z/SbcHjjnZXAvOai+fWnSoyfbCvjhu47LNGFbUVJ1PJb767rk3dc7/QjokYN+8qjUDNxczKFCB4eC5HgnHz3JFvrzxAJRz8Obsi2+pFUtdmvnIjL9/FwFMa+xxh9lcDt3IG/pC0OyHLArsrjM1bQmCVX5/FzpCWKArG72i38y//3vKDGotOsi08YJrQK4rhn2GqekU+AGucpqrumZqX9pKLMt1/HjeA49MaP3fDVSYs8lVbnV7rqs5cz4WuvaME8SJXq3e04t9peai3dGsF2LxclF10fPnAWMu0GhzoZ8dbdkfvBZ+FsxV62+OybArFzOEB3oZXUsj1zOtLpxdTg5HTK5sHdhD80K66XoSGfs/qRfPDjVbDOBoaDFdHmYKNnGGqMsNmDeUk7eurmdYZ1g8xuPvN6XL2WMHh4qt2soMgHHd8s/NDtWei5rnngqvZXHFGXnZ+yFbPCb6P//T4Gwfw4iJHnjQbiN13WZ/vCyI3lNTh9yOFSxdeQjf3RCV6zCX+yQNHU0L2+LM4akHZzhJtuP0RX2Z4Mp+dnPP3nKQPa7KKzNw29x7JOVgpJZTMLn3F2/wzGYwhQ6al/G1Nhq0TyxO6PvE39bkFvZHGZG/f8GL/d09+3Lvu6tOoVGfkQNZdLvPVA/zRD1q7GfsBWnjAR7Tn4zjk+idpbl3o9+DoZPTafpSs/dhWLmYacD2o3Sq9suN9zPy/vsGJ6Ob319mzlD9PFCZZvpoU9cRM0Z/TR1hRcaD9GiDSxy+7eIwmS/BO2Ye+gTnWC7HOyJ9GXcIDTnP3m4ZVx854DRuzG7PGQqN6/57ZeJQ4Tv7xnmPI7G8NIJ5MErb4iqvvuQhlweYpAPFK1P5qv/z6g7MBpdvT2hAnt1q2ezQnp4qWDhyWQupz1YDQJu9tz3aj9lm/lpphfV/1li35yj3x4sxPTlZWPRsXqTAjDO80nt6GW0fhNi8G6JVsiQzpnm25Mm+YzlGXMPTbuopbC50x/KR4ICnHpcVWpxz9t3ZJNBcMve7i2WOo8A0mcebuuTOxkn8/j68izwcfKwCMMrVXkidd16wvOkD28kLoHQK9ui5Wg2LeJ/G8gKzy0trz749HZCl7Line truncated
</defs>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

@@ -172,7 +172,7 @@
"guests": "الضيوف", "guests": "الضيوف",
"guest": "الضيف", "guest": "الضيف",
"web_conferencing_details_to_follow": "تفاصيل مؤتمرات الويب القادمة.", "web_conferencing_details_to_follow": "تفاصيل مؤتمرات الويب القادمة.",
"the_username": "اسم المستخدم", "404_the_user": "اسم المستخدم",
"username": "اسم المستخدم", "username": "اسم المستخدم",
"is_still_available": "لا يزال متاحًا.", "is_still_available": "لا يزال متاحًا.",
"documentation": "المستندات", "documentation": "المستندات",
@@ -183,7 +183,7 @@
"blog_description": "اقرأ أحدث أخبارنا ومقالاتنا", "blog_description": "اقرأ أحدث أخبارنا ومقالاتنا",
"join_our_community": "انضم إلى مجتمعنا", "join_our_community": "انضم إلى مجتمعنا",
"join_our_slack": "انضم إلى Slack الخاص بنا", "join_our_slack": "انضم إلى Slack الخاص بنا",
"claim_username_and_schedule_events": "احصل على اسم المستخدم وقم بجدولة الأحداث", "404_claim_entity_user": "احصل على اسم المستخدم وقم بجدولة الأحداث",
"popular_pages": "الصفحات الشائعة", "popular_pages": "الصفحات الشائعة",
"register_now": "التسجيل الآن", "register_now": "التسجيل الآن",
"register": "تسجيل", "register": "تسجيل",
@@ -231,7 +231,6 @@
"finish": "إنهاء", "finish": "إنهاء",
"few_sentences_about_yourself": "اكتب بضع جمل عن نفسك. سيظهر هذا على صفحة عنوان URL الشخصية لديك.", "few_sentences_about_yourself": "اكتب بضع جمل عن نفسك. سيظهر هذا على صفحة عنوان URL الشخصية لديك.",
"nearly_there": "أوشكت على الانتهاء!", "nearly_there": "أوشكت على الانتهاء!",
"nearly_there_instructions": "آخر شيء: تساعدك كتابة وصف موجز عنك ووضع صورة في الحصول على عمليات الحجز وإعلام الأشخاص بمَن سيحجزون معه حقًا.",
"set_availability_instructions": "حدد الفترات الزمنية التي تكون متاحًا فيها بشكل متكرر. يمكنك لاحقًا تحديد المزيد منها وربطها مع تقاويم مختلفة.", "set_availability_instructions": "حدد الفترات الزمنية التي تكون متاحًا فيها بشكل متكرر. يمكنك لاحقًا تحديد المزيد منها وربطها مع تقاويم مختلفة.",
"set_availability": "تحديد الوقت الذي تكون فيه متاحًا", "set_availability": "تحديد الوقت الذي تكون فيه متاحًا",
"continue_without_calendar": "المتابعة من دون تقويم", "continue_without_calendar": "المتابعة من دون تقويم",
@@ -1408,7 +1407,6 @@
"team_url_required": "يجب إدخال عنوان URL للفريق", "team_url_required": "يجب إدخال عنوان URL للفريق",
"team_url_taken": "عنوان URL هذا مأخوذ بالفعل", "team_url_taken": "عنوان URL هذا مأخوذ بالفعل",
"team_publish": "نشر فريق", "team_publish": "نشر فريق",
"number_sms_notifications": "رقم الهاتف (إشعارات الرسائل النصية)",
"attendee_email_variable": "اسم الحاضر", "attendee_email_variable": "اسم الحاضر",
"attendee_email_info": "البريد الإلكتروني للشخص الحجز", "attendee_email_info": "البريد الإلكتروني للشخص الحجز",
"kbar_search_placeholder": "اكتب أمرًا أو بحثًا...", "kbar_search_placeholder": "اكتب أمرًا أو بحثًا...",
@@ -172,7 +172,7 @@
"guests": "Hosté", "guests": "Hosté",
"guest": "Host", "guest": "Host",
"web_conferencing_details_to_follow": "Podrobnosti k videohovoru, které je třeba následovat.", "web_conferencing_details_to_follow": "Podrobnosti k videohovoru, které je třeba následovat.",
"the_username": "Uživatelské jméno", "404_the_user": "Uživatelské jméno",
"username": "Uživatelské jméno", "username": "Uživatelské jméno",
"is_still_available": "je stále dostupný.", "is_still_available": "je stále dostupný.",
"documentation": "Dokumentace", "documentation": "Dokumentace",
@@ -183,7 +183,7 @@
"blog_description": "Přečtěte si naše nejnovější novinky a články", "blog_description": "Přečtěte si naše nejnovější novinky a články",
"join_our_community": "Připojte se k naší komunitě", "join_our_community": "Připojte se k naší komunitě",
"join_our_slack": "Připojte se k našemu Slacku", "join_our_slack": "Připojte se k našemu Slacku",
"claim_username_and_schedule_events": "Nárokujte si své uživatelské jméno a plánujte události", "404_claim_entity_user": "Nárokujte si své uživatelské jméno a plánujte události",
"popular_pages": "Oblíbené stránky", "popular_pages": "Oblíbené stránky",
"register_now": "Zaregistrovat se nyní", "register_now": "Zaregistrovat se nyní",
"register": "Registrovat se", "register": "Registrovat se",
@@ -231,7 +231,6 @@
"finish": "Dokončit", "finish": "Dokončit",
"few_sentences_about_yourself": "Pár vět o vás. Budou se zobrazovat na URL vaší osobní stránky.", "few_sentences_about_yourself": "Pár vět o vás. Budou se zobrazovat na URL vaší osobní stránky.",
"nearly_there": "Téměř hotovo!", "nearly_there": "Téměř hotovo!",
"nearly_there_instructions": "A na závěr: Stručný text o vás a fotografie vám značně pomůžou v získávání rezervací. A ostatní díky tomu budou vědět, koho si rezervují.",
"set_availability_instructions": "Určete si časové intervaly, kdy jste pravidelně dostupní. Později můžete vytvořit další a přiřadit je různým kalendářům.", "set_availability_instructions": "Určete si časové intervaly, kdy jste pravidelně dostupní. Později můžete vytvořit další a přiřadit je různým kalendářům.",
"set_availability": "Nastavte, jak jste dostupní", "set_availability": "Nastavte, jak jste dostupní",
"continue_without_calendar": "Pokračovat bez kalendáře", "continue_without_calendar": "Pokračovat bez kalendáře",
@@ -1408,7 +1407,6 @@
"team_url_required": "Musíte zadat adresu URL týmu", "team_url_required": "Musíte zadat adresu URL týmu",
"team_url_taken": "Tato adresa URL je už obsazená", "team_url_taken": "Tato adresa URL je už obsazená",
"team_publish": "Zveřejnit tým", "team_publish": "Zveřejnit tým",
"number_sms_notifications": "Číslo telefonu (SMS oznámení)",
"attendee_email_variable": "E-mail účastníka", "attendee_email_variable": "E-mail účastníka",
"attendee_email_info": "E-mail osoby provádějící rezervaci", "attendee_email_info": "E-mail osoby provádějící rezervaci",
"kbar_search_placeholder": "Zadejte příkaz nebo vyhledejte...", "kbar_search_placeholder": "Zadejte příkaz nebo vyhledejte...",
@@ -165,7 +165,7 @@
"guests": "Gæster", "guests": "Gæster",
"guest": "Gæst", "guest": "Gæst",
"web_conferencing_details_to_follow": "Webkonference detaljer følger i bekræftelses-e-mailen.", "web_conferencing_details_to_follow": "Webkonference detaljer følger i bekræftelses-e-mailen.",
"the_username": "Brugernavnet", "404_the_user": "Brugernavnet",
"username": "Brugernavn", "username": "Brugernavn",
"is_still_available": "er stadig tilgængeligt.", "is_still_available": "er stadig tilgængeligt.",
"documentation": "Dokumentation", "documentation": "Dokumentation",
@@ -176,7 +176,7 @@
"blog_description": "Læs vores seneste nyheder og artikler", "blog_description": "Læs vores seneste nyheder og artikler",
"join_our_community": "Tilmeld dig vores fællesskab", "join_our_community": "Tilmeld dig vores fællesskab",
"join_our_slack": "Tilmeld dig vores Slack", "join_our_slack": "Tilmeld dig vores Slack",
"claim_username_and_schedule_events": "Få dit brugernavn og planlæg begivenheder", "404_claim_entity_user": "Få dit brugernavn og planlæg begivenheder",
"popular_pages": "Populære sider", "popular_pages": "Populære sider",
"register_now": "Tilmeld dig nu", "register_now": "Tilmeld dig nu",
"register": "Registrér", "register": "Registrér",
@@ -222,7 +222,6 @@
"finish": "Afslut", "finish": "Afslut",
"few_sentences_about_yourself": "Et par sætninger om dig selv. Dette vil blive vist på din personlige url side.", "few_sentences_about_yourself": "Et par sætninger om dig selv. Dette vil blive vist på din personlige url side.",
"nearly_there": "Du er der næsten!", "nearly_there": "Du er der næsten!",
"nearly_there_instructions": "Til sidst, en kort beskrivelse om dig og et foto vil virkelig hjælpe dig med at få bookinger og lade folk vide, hvem de booker med.",
"set_availability_instructions": "Definér tidsintervaller hvor du er tilgængelig på en tilbagevendende basis. Du kan oprette flere af disse senere og tildele dem til forskellige kalendere.", "set_availability_instructions": "Definér tidsintervaller hvor du er tilgængelig på en tilbagevendende basis. Du kan oprette flere af disse senere og tildele dem til forskellige kalendere.",
"set_availability": "Angiv din tilgængelighed", "set_availability": "Angiv din tilgængelighed",
"continue_without_calendar": "Fortsæt uden kalender", "continue_without_calendar": "Fortsæt uden kalender",
@@ -1344,7 +1343,6 @@
"team_url_required": "Der skal indtastes et team URL", "team_url_required": "Der skal indtastes et team URL",
"team_url_taken": "Denne URL er allerede i brug", "team_url_taken": "Denne URL er allerede i brug",
"team_publish": "Publicer team", "team_publish": "Publicer team",
"number_sms_notifications": "Telefonnummer (SMS notifikationer)",
"attendee_email_variable": "Deltagers e-mail", "attendee_email_variable": "Deltagers e-mail",
"attendee_email_info": "Personen der booker's e-mail", "attendee_email_info": "Personen der booker's e-mail",
"kbar_search_placeholder": "Indtast en kommando eller søgning...", "kbar_search_placeholder": "Indtast en kommando eller søgning...",
@@ -172,7 +172,7 @@
"guests": "Gäste", "guests": "Gäste",
"guest": "Gast", "guest": "Gast",
"web_conferencing_details_to_follow": "Web-Konferenzdetails folgen.", "web_conferencing_details_to_follow": "Web-Konferenzdetails folgen.",
"the_username": "Der Benutzername", "404_the_user": "Der Benutzername",
"username": "Benutzername", "username": "Benutzername",
"is_still_available": "ist noch verfügbar.", "is_still_available": "ist noch verfügbar.",
"documentation": "Dokumentation", "documentation": "Dokumentation",
@@ -183,7 +183,7 @@
"blog_description": "Lesen Sie unsere Neuigkeiten und Artikel", "blog_description": "Lesen Sie unsere Neuigkeiten und Artikel",
"join_our_community": "Treten Sie unserer Community bei", "join_our_community": "Treten Sie unserer Community bei",
"join_our_slack": "Treten Sie unserem Slack bei", "join_our_slack": "Treten Sie unserem Slack bei",
"claim_username_and_schedule_events": "Benutzername registrieren und Termine vergeben", "404_claim_entity_user": "Benutzername registrieren und Termine vergeben",
"popular_pages": "Beliebte Seiten", "popular_pages": "Beliebte Seiten",
"register_now": "Jetzt registrieren", "register_now": "Jetzt registrieren",
"register": "Registrieren", "register": "Registrieren",
@@ -231,7 +231,6 @@
"finish": "Fertig", "finish": "Fertig",
"few_sentences_about_yourself": "Schreiben Sie eine kurze Beschreibung, welche auf Ihrer persönlichen URL-Seite erscheinen wird.", "few_sentences_about_yourself": "Schreiben Sie eine kurze Beschreibung, welche auf Ihrer persönlichen URL-Seite erscheinen wird.",
"nearly_there": "Fast fertig", "nearly_there": "Fast fertig",
"nearly_there_instructions": "Zuletzt, eine kurze Beschreibung über Sie und ein Foto hilft, mehr Buchungen zu machen, da Kunden dann besser wissen, wen sie buchen.",
"set_availability_instructions": "Definieren Sie Zeiträume, wenn Sie wiederkehrend verfügbar sind. Sie können später weitere Zeiträume erstellen und verschiedenen Kalendern zuordnen.", "set_availability_instructions": "Definieren Sie Zeiträume, wenn Sie wiederkehrend verfügbar sind. Sie können später weitere Zeiträume erstellen und verschiedenen Kalendern zuordnen.",
"set_availability": "Verfügbarkeit festlegen", "set_availability": "Verfügbarkeit festlegen",
"continue_without_calendar": "Ohne Kalender fortfahren", "continue_without_calendar": "Ohne Kalender fortfahren",
@@ -747,7 +746,7 @@
"delete_managed_event_type": "Verwalteten Ereignistyp löschen?", "delete_managed_event_type": "Verwalteten Ereignistyp löschen?",
"delete_event_type_description": "Jede Person, mit der Sie diesen Link geteilt haben, kann nicht mehr über den Link buchen.", "delete_event_type_description": "Jede Person, mit der Sie diesen Link geteilt haben, kann nicht mehr über den Link buchen.",
"delete_managed_event_type_description": "<ul><li>Die Ereignistypen der diesem Ereignistypen zugewiesenen Mitglieder werden ebenfalls gelöscht.</li><li>Jeder, mit dem sie ihren Link geteilt haben, wird nicht mehr über diesen Link buchen können.</li></ul>", "delete_managed_event_type_description": "<ul><li>Die Ereignistypen der diesem Ereignistypen zugewiesenen Mitglieder werden ebenfalls gelöscht.</li><li>Jeder, mit dem sie ihren Link geteilt haben, wird nicht mehr über diesen Link buchen können.</li></ul>",
"confirm_delete_event_type": "<ul><li>Die Ereignistypen der diesem Ereignistypen zugewiesenen Mitglieder werden ebenfalls gelöscht.</li><li>Jeder, mit dem sie ihren Link geteilt haben, wird nicht mehr über diesen Link buchen können.</li></ul>", "confirm_delete_event_type": "Ja, löschen",
"delete_account": "Account löschen", "delete_account": "Account löschen",
"confirm_delete_account": "Ja, Account löschen", "confirm_delete_account": "Ja, Account löschen",
"delete_account_confirmation_message": "Sind Sie sicher, dass Sie Ihr {{appName}}-Konto löschen möchten? Sie können dann nicht mehr über Ihre geteilten Links gebucht werden und alle Einstellungen werden gelöscht.", "delete_account_confirmation_message": "Sind Sie sicher, dass Sie Ihr {{appName}}-Konto löschen möchten? Sie können dann nicht mehr über Ihre geteilten Links gebucht werden und alle Einstellungen werden gelöscht.",
@@ -1408,7 +1407,6 @@
"team_url_required": "Team-URL muss eingegeben werden", "team_url_required": "Team-URL muss eingegeben werden",
"team_url_taken": "Diese URL ist bereits vergeben", "team_url_taken": "Diese URL ist bereits vergeben",
"team_publish": "Team veröffentlichen", "team_publish": "Team veröffentlichen",
"number_sms_notifications": "Telefonnummer (SMS-Benachrichtigungen)",
"attendee_email_variable": "Teilnehmer E-Mail", "attendee_email_variable": "Teilnehmer E-Mail",
"attendee_email_info": "Die E-Mail-Adresse der buchenden Person", "attendee_email_info": "Die E-Mail-Adresse der buchenden Person",
"kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie ...", "kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie ...",
+21 -8
View File
@@ -187,7 +187,7 @@
"guests": "Guests", "guests": "Guests",
"guest": "Guest", "guest": "Guest",
"web_conferencing_details_to_follow": "Web conferencing details to follow in the confirmation email.", "web_conferencing_details_to_follow": "Web conferencing details to follow in the confirmation email.",
"the_username": "The username", "404_the_user": "The username",
"username": "Username", "username": "Username",
"is_still_available": "is still available.", "is_still_available": "is still available.",
"documentation": "Documentation", "documentation": "Documentation",
@@ -198,7 +198,7 @@
"blog_description": "Read our latest news and articles", "blog_description": "Read our latest news and articles",
"join_our_community": "Join our community", "join_our_community": "Join our community",
"join_our_slack": "Join our Slack", "join_our_slack": "Join our Slack",
"claim_username_and_schedule_events": "Claim your username and schedule events", "404_claim_entity_user": "Claim your username and schedule events",
"popular_pages": "Popular pages", "popular_pages": "Popular pages",
"register_now": "Register now", "register_now": "Register now",
"register": "Register", "register": "Register",
@@ -246,10 +246,10 @@
"available_apps": "Available Apps", "available_apps": "Available Apps",
"check_email_reset_password": "Check your email. We sent you a link to reset your password.", "check_email_reset_password": "Check your email. We sent you a link to reset your password.",
"finish": "Finish", "finish": "Finish",
"organization_general_description":"Manage settings for your team language and timezone", "organization_general_description": "Manage settings for your team language and timezone",
"few_sentences_about_yourself": "A few sentences about yourself. This will appear on your personal url page.", "few_sentences_about_yourself": "A few sentences about yourself. This will appear on your personal url page.",
"nearly_there": "Nearly there!", "nearly_there": "Nearly there!",
"nearly_there_instructions": "Last thing, a brief description about you and a photo really help you get bookings and let people know who they’re booking with.", "nearly_there_instructions": "Last thing, a brief description about you and a photo really helps you get bookings and let people know who they’re booking with.",
"set_availability_instructions": "Define ranges of time when you are available on a recurring basis. You can create more of these later and assign them to different calendars.", "set_availability_instructions": "Define ranges of time when you are available on a recurring basis. You can create more of these later and assign them to different calendars.",
"set_availability": "Set your availability", "set_availability": "Set your availability",
"continue_without_calendar": "Continue without calendar", "continue_without_calendar": "Continue without calendar",
@@ -339,6 +339,11 @@
"cancelling_event_recurring": "The event is one instance of a recurring event.", "cancelling_event_recurring": "The event is one instance of a recurring event.",
"cancelling_all_recurring": "These are all remaining instances in the recurring event.", "cancelling_all_recurring": "These are all remaining instances in the recurring event.",
"error_with_status_code_occured": "An error with status code {{status}} occurred.", "error_with_status_code_occured": "An error with status code {{status}} occurred.",
"error_event_type_url_duplicate": "An event type with this URL already exists.",
"error_event_type_unauthorized_create": "You are not able to create this event",
"error_event_type_unauthorized_update": "You are not able to edit this event",
"error_workflow_unauthorized_create": "You are not able to create this workflow",
"error_schedule_unauthorized_create": "You are not able to create this schedule",
"booking_already_cancelled": "This booking was already canceled", "booking_already_cancelled": "This booking was already canceled",
"booking_already_accepted_rejected": "This booking was already accepted or rejected", "booking_already_accepted_rejected": "This booking was already accepted or rejected",
"go_back_home": "Go back home", "go_back_home": "Go back home",
@@ -349,7 +354,6 @@
"no_status_bookings_yet_description": "You have no {{status}} bookings. {{description}}", "no_status_bookings_yet_description": "You have no {{status}} bookings. {{description}}",
"event_between_users": "{{eventName}} between {{host}} and {{attendeeName}}", "event_between_users": "{{eventName}} between {{host}} and {{attendeeName}}",
"bookings": "Bookings", "bookings": "Bookings",
"booking_not_found":"Booking not found",
"bookings_description": "See upcoming and past events booked through your event type links.", "bookings_description": "See upcoming and past events booked through your event type links.",
"upcoming_bookings": "As soon as someone books a time with you it will show up here.", "upcoming_bookings": "As soon as someone books a time with you it will show up here.",
"recurring_bookings": "As soon as someone books a recurring meeting with you it will show up here.", "recurring_bookings": "As soon as someone books a recurring meeting with you it will show up here.",
@@ -547,7 +551,7 @@
"team_description": "A few sentences about your team. This will appear on your team's url page.", "team_description": "A few sentences about your team. This will appear on your team's url page.",
"org_description": "A few sentances about your organization. This will appear on your organization's url page.", "org_description": "A few sentances about your organization. This will appear on your organization's url page.",
"members": "Members", "members": "Members",
"organization_members":"Organization members", "organization_members": "Organization members",
"member": "Member", "member": "Member",
"number_member_one": "{{count}} member", "number_member_one": "{{count}} member",
"number_member_other": "{{count}} members", "number_member_other": "{{count}} members",
@@ -897,6 +901,7 @@
"create_events_on": "Create events on", "create_events_on": "Create events on",
"enterprise_license": "This is an enterprise feature", "enterprise_license": "This is an enterprise feature",
"enterprise_license_description": "To enable this feature, have an administrator go to {{setupUrl}} to enter a license key. If a license key is already in place, please contact {{supportMail}} for help.", "enterprise_license_description": "To enable this feature, have an administrator go to {{setupUrl}} to enter a license key. If a license key is already in place, please contact {{supportMail}} for help.",
"enterprise_license_development": "You can test this feature on development mode. For production usage please have an administrator go to <2>/auth/setup</2> to enter a license key.",
"missing_license": "Missing License", "missing_license": "Missing License",
"signup_requires": "Commercial license required", "signup_requires": "Commercial license required",
"signup_requires_description": "{{companyName}} currently does not offer a free open source version of the sign up page. To receive full access to the signup components you need to acquire a commercial license. For personal use we recommend the Prisma Data Platform or any other Postgres interface to create accounts.", "signup_requires_description": "{{companyName}} currently does not offer a free open source version of the sign up page. To receive full access to the signup components you need to acquire a commercial license. For personal use we recommend the Prisma Data Platform or any other Postgres interface to create accounts.",
@@ -1466,7 +1471,7 @@
"team_url_required": "Must enter a team URL", "team_url_required": "Must enter a team URL",
"team_url_taken": "This URL is already taken", "team_url_taken": "This URL is already taken",
"team_publish": "Publish team", "team_publish": "Publish team",
"number_sms_notifications": "Phone number (SMS notifications)", "number_sms_notifications": "Phone number (SMS notifications)",
"attendee_email_variable": "Attendee email", "attendee_email_variable": "Attendee email",
"attendee_email_info": "The person booking's email", "attendee_email_info": "The person booking's email",
"kbar_search_placeholder": "Type a command or search...", "kbar_search_placeholder": "Type a command or search...",
@@ -1523,6 +1528,9 @@
"no_available_apps": "There are no available apps", "no_available_apps": "There are no available apps",
"no_available_apps_description": "Please ensure there are apps in your deployment under 'packages/app-store'", "no_available_apps_description": "Please ensure there are apps in your deployment under 'packages/app-store'",
"no_apps": "There are no apps enabled in this instance of Cal", "no_apps": "There are no apps enabled in this instance of Cal",
"no_apps_configured": "No app has been configured yet",
"enable_in_settings": "You can enable apps in the settings",
"please_contact_admin": "Please contact your admin",
"apps_settings": "Apps settings", "apps_settings": "Apps settings",
"fill_this_field": "Please fill in this field", "fill_this_field": "Please fill in this field",
"options": "Options", "options": "Options",
@@ -1726,7 +1734,6 @@
"app_is_connected": "{{dependencyName}} is connected", "app_is_connected": "{{dependencyName}} is connected",
"requires_app": "Requires {{dependencyName}}", "requires_app": "Requires {{dependencyName}}",
"verification_code": "Verification code", "verification_code": "Verification code",
"invalid_verification_link": "Invalid verification link",
"can_you_try_again": "Can you try again with a different time?", "can_you_try_again": "Can you try again with a different time?",
"verify": "Verify", "verify": "Verify",
"timezone_info": "The timezone of the person receiving", "timezone_info": "The timezone of the person receiving",
@@ -1889,9 +1896,15 @@
"my_profile": "My Profile", "my_profile": "My Profile",
"my_settings": "My Settings", "my_settings": "My Settings",
"sender_id_info": "Name or number shown as the sender of an SMS (some countries do not allow alphanumeric sender IDs)", "sender_id_info": "Name or number shown as the sender of an SMS (some countries do not allow alphanumeric sender IDs)",
"google_new_spam_policy": "Google’s new spam policy could prevent you from receiving any email and calendar notifications about this booking.",
"resolve": "Resolve",
"no_organization_slug": "There was an error creating teams for this organization. Missing URL slug.", "no_organization_slug": "There was an error creating teams for this organization. Missing URL slug.",
"org_name": "Organization name", "org_name": "Organization name",
"org_url": "Organization URL", "org_url": "Organization URL",
"copy_link_org": "Copy link to organization", "copy_link_org": "Copy link to organization",
"404_the_org": "The organization",
"404_the_team": "The team",
"404_claim_entity_org": "Claim your subdomain for your organization",
"404_claim_entity_team": "Claim this team and start managing schedules collectively",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
} }
@@ -172,7 +172,7 @@
"guests": "Invitados", "guests": "Invitados",
"guest": "Invitado", "guest": "Invitado",
"web_conferencing_details_to_follow": "Los detalles a seguir de su conferencia, en el correo de confirmación.", "web_conferencing_details_to_follow": "Los detalles a seguir de su conferencia, en el correo de confirmación.",
"the_username": "El Nombre de Usuario", "404_the_user": "El Nombre de Usuario",
"username": "Usuario", "username": "Usuario",
"is_still_available": "aún está disponible.", "is_still_available": "aún está disponible.",
"documentation": "Documentación", "documentation": "Documentación",
@@ -183,7 +183,7 @@
"blog_description": "Lee nuestras últimas noticias y artículos", "blog_description": "Lee nuestras últimas noticias y artículos",
"join_our_community": "Únete a nuestra comunidad", "join_our_community": "Únete a nuestra comunidad",
"join_our_slack": "Únete a nuestro Slack", "join_our_slack": "Únete a nuestro Slack",
"claim_username_and_schedule_events": "Reclama tu nombre de usuario y programa eventos", "404_claim_entity_user": "Reclama tu nombre de usuario y programa eventos",
"popular_pages": "Páginas Populares", "popular_pages": "Páginas Populares",
"register_now": "Regístrate Ahora", "register_now": "Regístrate Ahora",
"register": "Registrar", "register": "Registrar",
@@ -231,7 +231,6 @@
"finish": "Terminar", "finish": "Terminar",
"few_sentences_about_yourself": "Unas pocas frases sobre ti mismo. Esto aparecerá en tu página de url personal.", "few_sentences_about_yourself": "Unas pocas frases sobre ti mismo. Esto aparecerá en tu página de url personal.",
"nearly_there": "¡Ya casi está!", "nearly_there": "¡Ya casi está!",
"nearly_there_instructions": "Por último, una breve descripción de ti y una foto realmente te ayudan a hacer tus reservas y a informar a la gente con quién está reservando.",
"set_availability_instructions": "Defina los intervalos de tiempo cuando esté disponible de forma recurrente. Puede crear más tarde y asignarlos a diferentes calendarios.", "set_availability_instructions": "Defina los intervalos de tiempo cuando esté disponible de forma recurrente. Puede crear más tarde y asignarlos a diferentes calendarios.",
"set_availability": "Establecer Disponibilidad", "set_availability": "Establecer Disponibilidad",
"continue_without_calendar": "Continuar sin calendario", "continue_without_calendar": "Continuar sin calendario",
@@ -1408,7 +1407,6 @@
"team_url_required": "Debe introducir una URL del equipo", "team_url_required": "Debe introducir una URL del equipo",
"team_url_taken": "Esta URL ya está en uso", "team_url_taken": "Esta URL ya está en uso",
"team_publish": "Publicar equipo", "team_publish": "Publicar equipo",
"number_sms_notifications": "Número de teléfono (notificaciones por SMS)",
"attendee_email_variable": "Correo electrónico del asistente", "attendee_email_variable": "Correo electrónico del asistente",
"attendee_email_info": "El correo electrónico de la persona que reserva", "attendee_email_info": "El correo electrónico de la persona que reserva",
"kbar_search_placeholder": "Escriba un comando o búsqueda...", "kbar_search_placeholder": "Escriba un comando o búsqueda...",
+27 -13
View File
@@ -187,7 +187,7 @@
"guests": "Invités", "guests": "Invités",
"guest": "Invité(e)", "guest": "Invité(e)",
"web_conferencing_details_to_follow": "Les détails du rendez-vous sont à retrouver dans l'e-mail de confirmation.", "web_conferencing_details_to_follow": "Les détails du rendez-vous sont à retrouver dans l'e-mail de confirmation.",
"the_username": "Le nom d'utilisateur", "404_the_user": "Le nom d'utilisateur",
"username": "Nom d'utilisateur", "username": "Nom d'utilisateur",
"is_still_available": "est toujours disponible.", "is_still_available": "est toujours disponible.",
"documentation": "Documentation", "documentation": "Documentation",
@@ -198,7 +198,7 @@
"blog_description": "Lire nos dernières actualités et articles", "blog_description": "Lire nos dernières actualités et articles",
"join_our_community": "Rejoignez notre communauté", "join_our_community": "Rejoignez notre communauté",
"join_our_slack": "Rejoindre notre Slack", "join_our_slack": "Rejoindre notre Slack",
"claim_username_and_schedule_events": "Réservez votre nom d'utilisateur et planifiez des événements", "404_claim_entity_user": "Réservez votre nom d'utilisateur et planifiez des événements",
"popular_pages": "Pages populaires", "popular_pages": "Pages populaires",
"register_now": "S'inscrire maintenant", "register_now": "S'inscrire maintenant",
"register": "S'inscrire", "register": "S'inscrire",
@@ -339,6 +339,11 @@
"cancelling_event_recurring": "L'événement est une instance d'un événement récurrent.", "cancelling_event_recurring": "L'événement est une instance d'un événement récurrent.",
"cancelling_all_recurring": "Voici toutes les instances restantes dans l'événement récurrent.", "cancelling_all_recurring": "Voici toutes les instances restantes dans l'événement récurrent.",
"error_with_status_code_occured": "Une erreur avec le code de statut {{status}} est survenue.", "error_with_status_code_occured": "Une erreur avec le code de statut {{status}} est survenue.",
"error_event_type_url_duplicate": "Un type d'événement avec cette URL existe déjà.",
"error_event_type_unauthorized_create": "Vous n'êtes pas autorisé à créer cet événement",
"error_event_type_unauthorized_update": "Vous n'êtes pas autorisé à modifier cet événement",
"error_workflow_unauthorized_create": "Vous n'êtes pas autorisé à créer ce workflow",
"error_schedule_unauthorized_create": "Vous n'êtes pas autorisé à créer ce planning",
"booking_already_cancelled": "Cette réservation a déjà été annulée", "booking_already_cancelled": "Cette réservation a déjà été annulée",
"booking_already_accepted_rejected": "Cette réservation a déjà été acceptée ou refusée.", "booking_already_accepted_rejected": "Cette réservation a déjà été acceptée ou refusée.",
"go_back_home": "Retour à la page d'accueil", "go_back_home": "Retour à la page d'accueil",
@@ -349,7 +354,6 @@
"no_status_bookings_yet_description": "Vous n'avez pas de réservations {{status}}. {{description}}", "no_status_bookings_yet_description": "Vous n'avez pas de réservations {{status}}. {{description}}",
"event_between_users": "{{eventName}} entre {{host}} et {{attendeeName}}", "event_between_users": "{{eventName}} entre {{host}} et {{attendeeName}}",
"bookings": "Réservations", "bookings": "Réservations",
"booking_not_found": "Réservation introuvable",
"bookings_description": "Consultez les événements à venir et passés réservés via vos liens de type d'événement.", "bookings_description": "Consultez les événements à venir et passés réservés via vos liens de type d'événement.",
"upcoming_bookings": "Dès que quelqu'un réservera un rendez-vous avec vous, il apparaîtra ici.", "upcoming_bookings": "Dès que quelqu'un réservera un rendez-vous avec vous, il apparaîtra ici.",
"recurring_bookings": "Dès que quelqu'un réserve un rendez-vous récurrent avec vous, il apparaît ici.", "recurring_bookings": "Dès que quelqu'un réserve un rendez-vous récurrent avec vous, il apparaît ici.",
@@ -622,7 +626,7 @@
"default_duration_no_options": "Veuillez d'abord choisir les durées disponibles", "default_duration_no_options": "Veuillez d'abord choisir les durées disponibles",
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)", "multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
"minutes": "minutes", "minutes": "minutes",
"round_robin": "Round-Robin", "round_robin": "Round-robin",
"round_robin_description": "Alternez vos rendez-vous entre plusieurs membres d'équipe.", "round_robin_description": "Alternez vos rendez-vous entre plusieurs membres d'équipe.",
"managed_event": "Événement géré", "managed_event": "Événement géré",
"username_placeholder": "nom d'utilisateur", "username_placeholder": "nom d'utilisateur",
@@ -897,6 +901,7 @@
"create_events_on": "Créer des événements dans :", "create_events_on": "Créer des événements dans :",
"enterprise_license": "Il s'agit d'une fonctionnalité d'entreprise", "enterprise_license": "Il s'agit d'une fonctionnalité d'entreprise",
"enterprise_license_description": "Pour activer cette fonctionnalité, demandez à un administrateur d'accéder à {{setupUrl}} pour saisir une clé de licence. Si une clé de licence est déjà en place, veuillez contacter {{supportMail}} pour obtenir de l'aide.", "enterprise_license_description": "Pour activer cette fonctionnalité, demandez à un administrateur d'accéder à {{setupUrl}} pour saisir une clé de licence. Si une clé de licence est déjà en place, veuillez contacter {{supportMail}} pour obtenir de l'aide.",
"enterprise_license_development": "Vous pouvez tester cette fonctionnalité en mode développement. Pour une utilisation en production, veuillez demander à un administrateur d'aller à <2>/auth/setup</2> pour entrer une clé de licence.",
"missing_license": "Licence manquante", "missing_license": "Licence manquante",
"signup_requires": "Licence commerciale requise", "signup_requires": "Licence commerciale requise",
"signup_requires_description": "{{companyName}} ne propose actuellement pas de version open source gratuite de la page d'inscription. Pour recevoir un accès complet aux composants d'inscription, vous devez acquérir une licence commerciale. Pour un usage personnel, nous recommandons la plateforme de données Prisma ou toute autre interface Postgres pour créer des comptes.", "signup_requires_description": "{{companyName}} ne propose actuellement pas de version open source gratuite de la page d'inscription. Pour recevoir un accès complet aux composants d'inscription, vous devez acquérir une licence commerciale. Pour un usage personnel, nous recommandons la plateforme de données Prisma ou toute autre interface Postgres pour créer des comptes.",
@@ -1405,7 +1410,7 @@
"manage_billing": "Gérer la facturation", "manage_billing": "Gérer la facturation",
"manage_billing_description": "Gérez tout ce qui est en lien avec la facturation.", "manage_billing_description": "Gérez tout ce qui est en lien avec la facturation.",
"billing_freeplan_title": "Vous êtes actuellement sur le plan Gratuit", "billing_freeplan_title": "Vous êtes actuellement sur le plan Gratuit",
"billing_freeplan_description": "Nous travaillons mieux en équipe. Élargissez vos workflows avec le Round-Robin et les événements collectifs et produisez des formulaires de routage avancés.", "billing_freeplan_description": "Nous travaillons mieux en équipe. Élargissez vos workflows avec les événements round-robin et collectifs et produisez des formulaires de routage avancés.",
"billing_freeplan_cta": "Essayer maintenant", "billing_freeplan_cta": "Essayer maintenant",
"billing_portal": "Portail de facturation", "billing_portal": "Portail de facturation",
"billing_help_cta": "Contacter l'assistance", "billing_help_cta": "Contacter l'assistance",
@@ -1487,11 +1492,11 @@
"collective_scheduling": "Planification collective", "collective_scheduling": "Planification collective",
"make_it_easy_to_book": "Facilitez la réservation de votre équipe lorsque tout le monde est disponible.", "make_it_easy_to_book": "Facilitez la réservation de votre équipe lorsque tout le monde est disponible.",
"find_the_best_person": "Trouvez la meilleure personne disponible et alternez à travers votre équipe.", "find_the_best_person": "Trouvez la meilleure personne disponible et alternez à travers votre équipe.",
"fixed_round_robin": "Round-Robin fixe", "fixed_round_robin": "Round-robin fixe",
"add_one_fixed_attendee": "Ajoutez un participant fixe et le Round-Robin via un certain nombre de participants.", "add_one_fixed_attendee": "Ajoutez un participant fixe et le round-robin via un certain nombre de participants.",
"calcom_is_better_with_team": "{{appName}} est meilleur en équipe", "calcom_is_better_with_team": "{{appName}} est meilleur en équipe",
"the_calcom_team": "L'équipe {{companyName}}", "the_calcom_team": "L'équipe {{companyName}}",
"add_your_team_members": "Ajoutez les membres de votre équipe à vos types d'événements. Utilisez la planification collective pour inclure tout le monde ou trouvez la personne la plus appropriée avec la planification Round-Robin.", "add_your_team_members": "Ajoutez les membres de votre équipe à vos types d'événements. Utilisez la planification collective pour inclure tout le monde ou trouvez la personne la plus appropriée avec la planification round-robin.",
"booking_limit_reached": "La limite de réservation pour ce type d'événement a été atteinte", "booking_limit_reached": "La limite de réservation pour ce type d'événement a été atteinte",
"duration_limit_reached": "La limite de durée pour ce type d'événement a été atteinte", "duration_limit_reached": "La limite de durée pour ce type d'événement a été atteinte",
"admin_has_disabled": "Un administrateur a désactivé {{appName}}", "admin_has_disabled": "Un administrateur a désactivé {{appName}}",
@@ -1523,6 +1528,9 @@
"no_available_apps": "Il n'y a aucune application disponible", "no_available_apps": "Il n'y a aucune application disponible",
"no_available_apps_description": "Veuillez vous assurer qu'il y a des applications dans votre déploiement sous \"packages/app-store\"", "no_available_apps_description": "Veuillez vous assurer qu'il y a des applications dans votre déploiement sous \"packages/app-store\"",
"no_apps": "Aucune application n'est activée dans cette instance de Cal", "no_apps": "Aucune application n'est activée dans cette instance de Cal",
"no_apps_configured": "Aucune application n'a encore été configurée",
"enable_in_settings": "Vous pouvez activer les applications dans les paramètres",
"please_contact_admin": "Veuillez contacter votre administrateur",
"apps_settings": "Paramètres des applications", "apps_settings": "Paramètres des applications",
"fill_this_field": "Veuillez remplir ce champ", "fill_this_field": "Veuillez remplir ce champ",
"options": "Options", "options": "Options",
@@ -1569,7 +1577,7 @@
"assignment": "Affectation", "assignment": "Affectation",
"fixed_hosts": "Hôtes fixes", "fixed_hosts": "Hôtes fixes",
"add_fixed_hosts": "Ajouter des hôtes fixes", "add_fixed_hosts": "Ajouter des hôtes fixes",
"round_robin_hosts": "Hôtes Round-Robin", "round_robin_hosts": "Hôtes round-robin",
"minimum_round_robin_hosts_count": "Nombre d'hôtes requis pour participer", "minimum_round_robin_hosts_count": "Nombre d'hôtes requis pour participer",
"hosts": "Hôtes", "hosts": "Hôtes",
"upgrade_to_enable_feature": "Vous devez créer une équipe pour activer cette fonctionnalité. Cliquez pour créer une équipe.", "upgrade_to_enable_feature": "Vous devez créer une équipe pour activer cette fonctionnalité. Cliquez pour créer une équipe.",
@@ -1649,8 +1657,8 @@
"create_a_managed_event": "Créer un type d'événement géré", "create_a_managed_event": "Créer un type d'événement géré",
"meetings_are_better_with_the_right": "Les rendez-vous sont meilleurs avec les bons membres d'équipe. Invitez-les maintenant.", "meetings_are_better_with_the_right": "Les rendez-vous sont meilleurs avec les bons membres d'équipe. Invitez-les maintenant.",
"create_a_one_one_template": "Créez un modèle unique pour un type d'événement et distribuez-le à plusieurs membres.", "create_a_one_one_template": "Créez un modèle unique pour un type d'événement et distribuez-le à plusieurs membres.",
"collective_or_roundrobin": "Collective ou Round-Robin", "collective_or_roundrobin": "Collective ou round-robin",
"book_your_team_members": "Réservez les membres de votre équipe entre eux avec des événements collectifs ou mettez en place un cycle pour obtenir la bonne personne avec le Round-Robin.", "book_your_team_members": "Réservez les membres de votre équipe entre eux avec des événements collectifs ou mettez en place un cycle pour obtenir la bonne personne avec le round-robin.",
"event_no_longer_attending_subject": "Ne participe plus à {{title}} le {{date}}", "event_no_longer_attending_subject": "Ne participe plus à {{title}} le {{date}}",
"no_longer_attending": "Vous ne participez plus à cet événement", "no_longer_attending": "Vous ne participez plus à cet événement",
"attendee_no_longer_attending_subject": "Un participant ne participe plus à {{title}} le {{date}}", "attendee_no_longer_attending_subject": "Un participant ne participe plus à {{title}} le {{date}}",
@@ -1726,7 +1734,6 @@
"app_is_connected": "{{dependencyName}} est connectée", "app_is_connected": "{{dependencyName}} est connectée",
"requires_app": "Requiert {{dependencyName}}", "requires_app": "Requiert {{dependencyName}}",
"verification_code": "Code de vérification", "verification_code": "Code de vérification",
"invalid_verification_link": "Lien de vérification introuvable",
"can_you_try_again": "Pouvez-vous réessayer avec un autre créneau ?", "can_you_try_again": "Pouvez-vous réessayer avec un autre créneau ?",
"verify": "Vérifier", "verify": "Vérifier",
"timezone_info": "Le fuseau horaire du destinataire", "timezone_info": "Le fuseau horaire du destinataire",
@@ -1833,6 +1840,7 @@
"pop_up_element_click": "Clic sur un élément", "pop_up_element_click": "Clic sur un élément",
"open_dialog_with_element_click": "Ouvre votre boîte de dialogue Cal lorsque quelqu'un clique sur un élément.", "open_dialog_with_element_click": "Ouvre votre boîte de dialogue Cal lorsque quelqu'un clique sur un élément.",
"need_help_embedding": "Besoin d'aide ? Consultez nos guides pour intégrer Cal sur Wix, Squarespace ou WordPress, consultez nos questions fréquentes ou explorez les options d'intégration avancées.", "need_help_embedding": "Besoin d'aide ? Consultez nos guides pour intégrer Cal sur Wix, Squarespace ou WordPress, consultez nos questions fréquentes ou explorez les options d'intégration avancées.",
"book_my_cal": "Prendre rendez-vous",
"invite_as": "Inviter en tant que", "invite_as": "Inviter en tant que",
"form_updated_successfully": "Formulaire mis à jour avec succès.", "form_updated_successfully": "Formulaire mis à jour avec succès.",
"disable_attendees_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour les participants", "disable_attendees_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour les participants",
@@ -1846,7 +1854,7 @@
"first_event_type_webhook_description": "Créez votre premier webhook pour ce type d'événement", "first_event_type_webhook_description": "Créez votre premier webhook pour ce type d'événement",
"create_for": "Créer pour", "create_for": "Créer pour",
"setup_organization": "Configurer une organisation", "setup_organization": "Configurer une organisation",
"organization_banner_description": "Créez un environnement où vos équipes peuvent créer des applications partagées, des workflows et des types d'événements avec une planification Round-Robin et collective.", "organization_banner_description": "Créez un environnement où vos équipes peuvent créer des applications partagées, des workflows et des types d'événements avec une planification round-robin et collective.",
"organization_banner_title": "Gérer les organisations avec plusieurs équipes", "organization_banner_title": "Gérer les organisations avec plusieurs équipes",
"set_up_your_organization": "Configurer votre organisation", "set_up_your_organization": "Configurer votre organisation",
"organizations_description": "Les organisations sont des environnements partagés dans lesquels les équipes peuvent créer des types d'événements partagés, des applications, des workflows, etc.", "organizations_description": "Les organisations sont des environnements partagés dans lesquels les équipes peuvent créer des types d'événements partagés, des applications, des workflows, etc.",
@@ -1888,9 +1896,15 @@
"my_profile": "Mon profil", "my_profile": "Mon profil",
"my_settings": "Mes paramètres", "my_settings": "Mes paramètres",
"sender_id_info": "Nom ou numéro affiché comme expéditeur d'un SMS (certains pays n'autorisent pas les ID d'expéditeur alphanumériques)", "sender_id_info": "Nom ou numéro affiché comme expéditeur d'un SMS (certains pays n'autorisent pas les ID d'expéditeur alphanumériques)",
"google_new_spam_policy": "La nouvelle politique anti-spam de Google peut vous empêcher de recevoir des notifications par e-mail ou sur votre calendrier concernant cette réservation.",
"resolve": "Résoudre",
"no_organization_slug": "Une erreur s'est produite lors de la création des équipes pour cette organisation. Le slug du lien est manquant.", "no_organization_slug": "Une erreur s'est produite lors de la création des équipes pour cette organisation. Le slug du lien est manquant.",
"org_name": "Nom de l'organisation", "org_name": "Nom de l'organisation",
"org_url": "Lien de l'organisation", "org_url": "Lien de l'organisation",
"copy_link_org": "Copier le lien vers l’organisation", "copy_link_org": "Copier le lien vers l’organisation",
"404_the_org": "L'organisation",
"404_the_team": "L'équipe",
"404_claim_entity_org": "Réservez votre sous-domaine pour votre organisation",
"404_claim_entity_team": "Revendiquez cette équipe et commencez à gérer vos plannings collectivement",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
} }
@@ -179,7 +179,7 @@
"guests": "אורחים", "guests": "אורחים",
"guest": "אורח", "guest": "אורח",
"web_conferencing_details_to_follow": "פרטי שיחת הוועידה המקוונת, הכלולים בדוא\"ל האישור, שיש לפעול על פיהם.", "web_conferencing_details_to_follow": "פרטי שיחת הוועידה המקוונת, הכלולים בדוא\"ל האישור, שיש לפעול על פיהם.",
"the_username": "שם המשתמש", "404_the_user": "שם המשתמש",
"username": "שם משתמש", "username": "שם משתמש",
"is_still_available": "עדיין זמין.", "is_still_available": "עדיין זמין.",
"documentation": "תיעוד", "documentation": "תיעוד",
@@ -190,7 +190,7 @@
"blog_description": "לעיון בחדשות ובמאמרים האחרונים שלנו", "blog_description": "לעיון בחדשות ובמאמרים האחרונים שלנו",
"join_our_community": "הצטרף לקהילה שלנו", "join_our_community": "הצטרף לקהילה שלנו",
"join_our_slack": "הצטרף לצ׳אט שלנו ב-Slack", "join_our_slack": "הצטרף לצ׳אט שלנו ב-Slack",
"claim_username_and_schedule_events": "קבל את שם המשתמש שלך והתחל לקבוע מועדים לאירועים", "404_claim_entity_user": "קבל את שם המשתמש שלך והתחל לקבוע מועדים לאירועים",
"popular_pages": "דפים פופולריים", "popular_pages": "דפים פופולריים",
"register_now": "להירשם עכשיו", "register_now": "להירשם עכשיו",
"register": "הרשמה", "register": "הרשמה",
@@ -239,7 +239,6 @@
"finish": "סיום", "finish": "סיום",
"few_sentences_about_yourself": "מספר משפטים אודותיך. המידע הזה יופיע בדף ה-URL האישי שלך.", "few_sentences_about_yourself": "מספר משפטים אודותיך. המידע הזה יופיע בדף ה-URL האישי שלך.",
"nearly_there": "כמעט סיימנו!", "nearly_there": "כמעט סיימנו!",
"nearly_there_instructions": "דבר אחרון: תיאור קצר אודותיך בתוספת תמונה ממש עוזרים להשיג הזמנות ומאפשרים לאנשים לדעת עם מי הם עומדים להיפגש.",
"set_availability_instructions": "הגדר טווחי זמן שבהם אתה זמין באופן קבוע. ניתן יהיה ליצור טווחי זמן נוספים מאוחר יותר ולהקצות אותם ללוחות שנה אחרים.", "set_availability_instructions": "הגדר טווחי זמן שבהם אתה זמין באופן קבוע. ניתן יהיה ליצור טווחי זמן נוספים מאוחר יותר ולהקצות אותם ללוחות שנה אחרים.",
"set_availability": "ציין את הזמינות שלך", "set_availability": "ציין את הזמינות שלך",
"continue_without_calendar": "להמשיך בלי לוח שנה", "continue_without_calendar": "להמשיך בלי לוח שנה",
@@ -1421,7 +1420,6 @@
"team_url_required": "יש להזין כתובת URL של הצוות", "team_url_required": "יש להזין כתובת URL של הצוות",
"team_url_taken": "כתובת ה-URL הזו כבר תפוסה", "team_url_taken": "כתובת ה-URL הזו כבר תפוסה",
"team_publish": "פרסום צוות", "team_publish": "פרסום צוות",
"number_sms_notifications": "מספר טלפון (התראות SMS)",
"attendee_email_variable": "כתובת הדוא\"ל של המשתתף", "attendee_email_variable": "כתובת הדוא\"ל של המשתתף",
"attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה", "attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה",
"kbar_search_placeholder": "הקלד/י פקודה או חפש/י...", "kbar_search_placeholder": "הקלד/י פקודה או חפש/י...",
@@ -161,7 +161,7 @@
"guests": "Gosti", "guests": "Gosti",
"guest": "Gost", "guest": "Gost",
"web_conferencing_details_to_follow": "Pojedinosti o web konferenciji slijede u potvrdnoj e-poruci.", "web_conferencing_details_to_follow": "Pojedinosti o web konferenciji slijede u potvrdnoj e-poruci.",
"the_username": "Korisničko ime", "404_the_user": "Korisničko ime",
"username": "Korisničko ime", "username": "Korisničko ime",
"is_still_available": "je i dalje dostupno.", "is_still_available": "je i dalje dostupno.",
"documentation": "Dokumentacija", "documentation": "Dokumentacija",
@@ -172,7 +172,7 @@
"blog_description": "Pročitajte naše najnovije vijesti i članke", "blog_description": "Pročitajte naše najnovije vijesti i članke",
"join_our_community": "Pridružite se našoj zajednici", "join_our_community": "Pridružite se našoj zajednici",
"join_our_slack": "Pridružite se na naš Slack", "join_our_slack": "Pridružite se na naš Slack",
"claim_username_and_schedule_events": "Zatražite svoje korisničko ime i zakažite događaje", "404_claim_entity_user": "Zatražite svoje korisničko ime i zakažite događaje",
"popular_pages": "Popularne stranice", "popular_pages": "Popularne stranice",
"register_now": "Registriraj se sad", "register_now": "Registriraj se sad",
"register": "Registriraj se", "register": "Registriraj se",
@@ -218,7 +218,6 @@
"finish": "Završi", "finish": "Završi",
"few_sentences_about_yourself": "Nekoliko rečenica o sebi. Ovo će se pojaviti na vašoj osobnoj stranici.", "few_sentences_about_yourself": "Nekoliko rečenica o sebi. Ovo će se pojaviti na vašoj osobnoj stranici.",
"nearly_there": "Skoro pa gotovo!", "nearly_there": "Skoro pa gotovo!",
"nearly_there_instructions": "Posljednja stvar, vaš kratki opis i fotografija stvarno pomažu da dobijete rezervacije i daju ljudima do znanja kod koga rezerviraju.",
"set_availability_instructions": "Definirajte periode kad ste stalno dostupni. Kasnije možete kreirati više njih i dodijeliti ih različitim kalendarima.", "set_availability_instructions": "Definirajte periode kad ste stalno dostupni. Kasnije možete kreirati više njih i dodijeliti ih različitim kalendarima.",
"set_availability": "Postavite svoju dostupnost", "set_availability": "Postavite svoju dostupnost",
"continue_without_calendar": "Nastavite bez kalendara", "continue_without_calendar": "Nastavite bez kalendara",
@@ -180,7 +180,7 @@
"guests": "Ospiti", "guests": "Ospiti",
"guest": "Ospite", "guest": "Ospite",
"web_conferencing_details_to_follow": "Dettagli della conferenza web da seguire.", "web_conferencing_details_to_follow": "Dettagli della conferenza web da seguire.",
"the_username": "Il nome utente", "404_the_user": "Il nome utente",
"username": "Username", "username": "Username",
"is_still_available": "è ancora disponibile.", "is_still_available": "è ancora disponibile.",
"documentation": "Documentazione", "documentation": "Documentazione",
@@ -191,7 +191,7 @@
"blog_description": "Leggi le nostre ultime notizie e articoli", "blog_description": "Leggi le nostre ultime notizie e articoli",
"join_our_community": "Unisciti alla nostra community", "join_our_community": "Unisciti alla nostra community",
"join_our_slack": "Unisciti al nostro Slack", "join_our_slack": "Unisciti al nostro Slack",
"claim_username_and_schedule_events": "Richiedi il tuo nome utente e pianifica eventi", "404_claim_entity_user": "Richiedi il tuo nome utente e pianifica eventi",
"popular_pages": "Pagine popolari", "popular_pages": "Pagine popolari",
"register_now": "Registrati ora", "register_now": "Registrati ora",
"register": "Registrati", "register": "Registrati",
@@ -240,7 +240,6 @@
"finish": "Fine", "finish": "Fine",
"few_sentences_about_yourself": "Alcune frasi su di te. Questo apparirà sulla tua pagina url personale.", "few_sentences_about_yourself": "Alcune frasi su di te. Questo apparirà sulla tua pagina url personale.",
"nearly_there": "Ci siamo quasi", "nearly_there": "Ci siamo quasi",
"nearly_there_instructions": "Ultima cosa, una breve descrizione di te e una foto ti aiutano davvero a ottenere prenotazioni e far sapere alle persone con chi stanno prenotando.",
"set_availability_instructions": "Definisci intervalli di tempo di quando sei disponibile su una base ricorrente. Puoi crearne di più in seguito e assegnarli a calendari diversi.", "set_availability_instructions": "Definisci intervalli di tempo di quando sei disponibile su una base ricorrente. Puoi crearne di più in seguito e assegnarli a calendari diversi.",
"set_availability": "Imposta la tua disponibilità", "set_availability": "Imposta la tua disponibilità",
"continue_without_calendar": "Continua senza calendario", "continue_without_calendar": "Continua senza calendario",
@@ -1438,7 +1437,6 @@
"team_url_required": "Immettere un URL per il team", "team_url_required": "Immettere un URL per il team",
"team_url_taken": "URL già occupato", "team_url_taken": "URL già occupato",
"team_publish": "Pubblica team", "team_publish": "Pubblica team",
"number_sms_notifications": "Numero di telefono (notifiche SMS)",
"attendee_email_variable": "E-mail partecipante", "attendee_email_variable": "E-mail partecipante",
"attendee_email_info": "E-mail della persona che prenota", "attendee_email_info": "E-mail della persona che prenota",
"kbar_search_placeholder": "Digita un comando o esegui una ricerca...", "kbar_search_placeholder": "Digita un comando o esegui una ricerca...",
@@ -172,7 +172,7 @@
"guests": "ゲスト", "guests": "ゲスト",
"guest": "ゲスト", "guest": "ゲスト",
"web_conferencing_details_to_follow": "ウェブ会議の詳細には確認メールでお送りします。", "web_conferencing_details_to_follow": "ウェブ会議の詳細には確認メールでお送りします。",
"the_username": "ユーザー名", "404_the_user": "ユーザー名",
"username": "ユーザー名", "username": "ユーザー名",
"is_still_available": "まだ利用可能。", "is_still_available": "まだ利用可能。",
"documentation": "文書", "documentation": "文書",
@@ -183,7 +183,7 @@
"blog_description": "最新のニュースや記事を読む", "blog_description": "最新のニュースや記事を読む",
"join_our_community": "コミュニティーに参加する", "join_our_community": "コミュニティーに参加する",
"join_our_slack": "Slack に参加する", "join_our_slack": "Slack に参加する",
"claim_username_and_schedule_events": "ユーザー名を獲得してイベントをスケジュールする", "404_claim_entity_user": "ユーザー名を獲得してイベントをスケジュールする",
"popular_pages": "人気のページ", "popular_pages": "人気のページ",
"register_now": "今すぐ登録", "register_now": "今すぐ登録",
"register": "登録", "register": "登録",
@@ -231,7 +231,6 @@
"finish": "完了", "finish": "完了",
"few_sentences_about_yourself": "あなたについてのいくつかの文章。これはあなたの個人URLページに表示されます。", "few_sentences_about_yourself": "あなたについてのいくつかの文章。これはあなたの個人URLページに表示されます。",
"nearly_there": "あと少しで完了です!", "nearly_there": "あと少しで完了です!",
"nearly_there_instructions": "最後に、あなたについての簡単な説明と写真は、あなたが予約を取得し、誰と一緒に予約しているかを人々に知らせるのに役立ちます。",
"set_availability_instructions": "定期的に利用できる時間の範囲を定義します。後でこれらをさらに作成し、別のカレンダーに割り当てることができます。", "set_availability_instructions": "定期的に利用できる時間の範囲を定義します。後でこれらをさらに作成し、別のカレンダーに割り当てることができます。",
"set_availability": "利用可否の設定", "set_availability": "利用可否の設定",
"continue_without_calendar": "カレンダーなしで続行", "continue_without_calendar": "カレンダーなしで続行",
@@ -1408,7 +1407,6 @@
"team_url_required": "チームの URL の入力は必須です", "team_url_required": "チームの URL の入力は必須です",
"team_url_taken": "この URL は既に使用されています", "team_url_taken": "この URL は既に使用されています",
"team_publish": "チームを公開", "team_publish": "チームを公開",
"number_sms_notifications": "電話番号(SMS 通知)",
"attendee_email_variable": "出席者のメールアドレス", "attendee_email_variable": "出席者のメールアドレス",
"attendee_email_info": "予約者のメールアドレス", "attendee_email_info": "予約者のメールアドレス",
"kbar_search_placeholder": "コマンドを入力するか、検索してください...", "kbar_search_placeholder": "コマンドを入力するか、検索してください...",
@@ -173,7 +173,7 @@
"guests": "게스트", "guests": "게스트",
"guest": "게스트", "guest": "게스트",
"web_conferencing_details_to_follow": "따라야 할 웹 회의 세부 정보.", "web_conferencing_details_to_follow": "따라야 할 웹 회의 세부 정보.",
"the_username": "사용자 이름", "404_the_user": "사용자 이름",
"username": "사용자 이름", "username": "사용자 이름",
"is_still_available": "아직 사용할 수 있습니다.", "is_still_available": "아직 사용할 수 있습니다.",
"documentation": "정보 관리", "documentation": "정보 관리",
@@ -184,7 +184,7 @@
"blog_description": "최신 뉴스 및 기사 읽기", "blog_description": "최신 뉴스 및 기사 읽기",
"join_our_community": "커뮤니티 가입하기", "join_our_community": "커뮤니티 가입하기",
"join_our_slack": "슬랙 가입하기", "join_our_slack": "슬랙 가입하기",
"claim_username_and_schedule_events": "사용자 이름을 입력하고 이벤트를 만드세요.", "404_claim_entity_user": "사용자 이름을 입력하고 이벤트를 만드세요.",
"popular_pages": "인기 페이지", "popular_pages": "인기 페이지",
"register_now": "지금 등록하세요", "register_now": "지금 등록하세요",
"register": "등록하기", "register": "등록하기",
@@ -232,7 +232,6 @@
"finish": "끝", "finish": "끝",
"few_sentences_about_yourself": "자신에 대해 몇 마디를 써보세요. 개인 URL 페이지에 보이는 내용입니다.", "few_sentences_about_yourself": "자신에 대해 몇 마디를 써보세요. 개인 URL 페이지에 보이는 내용입니다.",
"nearly_there": "거의 다 되었습니다!", "nearly_there": "거의 다 되었습니다!",
"nearly_there_instructions": "마지막으로, 당신에 대해 간단한 소개와 사진을 올려주세요. 소개와 사진은 예약에 도움을 줍니다.",
"set_availability_instructions": "주기적으로 시간이 되는 때가 언제인지 알려주세요. 나중에 더 추가할 수 있습니다.", "set_availability_instructions": "주기적으로 시간이 되는 때가 언제인지 알려주세요. 나중에 더 추가할 수 있습니다.",
"set_availability": "언제 여유가 있는지 설정하세요.", "set_availability": "언제 여유가 있는지 설정하세요.",
"continue_without_calendar": "캘린더 없이 계속하기", "continue_without_calendar": "캘린더 없이 계속하기",
@@ -1409,7 +1408,6 @@
"team_url_required": "팀 URL을 입력하세요", "team_url_required": "팀 URL을 입력하세요",
"team_url_taken": "이미 사용 중인 URL입니다", "team_url_taken": "이미 사용 중인 URL입니다",
"team_publish": "팀 게시", "team_publish": "팀 게시",
"number_sms_notifications": "전화번호 (SMS notifications)",
"attendee_email_variable": "참석자 이메일", "attendee_email_variable": "참석자 이메일",
"attendee_email_info": "예약자 이메일", "attendee_email_info": "예약자 이메일",
"kbar_search_placeholder": "명령어를 입력하거나 검색하세요...", "kbar_search_placeholder": "명령어를 입력하거나 검색하세요...",
@@ -172,7 +172,7 @@
"guests": "Bezoekers", "guests": "Bezoekers",
"guest": "Gast", "guest": "Gast",
"web_conferencing_details_to_follow": "Details van de web conferentie zullen volgen.", "web_conferencing_details_to_follow": "Details van de web conferentie zullen volgen.",
"the_username": "De gebruikersnaam", "404_the_user": "De gebruikersnaam",
"username": "Gebruikersnaam", "username": "Gebruikersnaam",
"is_still_available": "is nog steeds beschikbaar.", "is_still_available": "is nog steeds beschikbaar.",
"documentation": "Documentatie", "documentation": "Documentatie",
@@ -183,7 +183,7 @@
"blog_description": "Lees ons laatste nieuws en artikelen", "blog_description": "Lees ons laatste nieuws en artikelen",
"join_our_community": "Word lid van onze community", "join_our_community": "Word lid van onze community",
"join_our_slack": "Bezoek onze Slack", "join_our_slack": "Bezoek onze Slack",
"claim_username_and_schedule_events": "Claim uw gebruikersnaam en plan evenementen", "404_claim_entity_user": "Claim uw gebruikersnaam en plan evenementen",
"popular_pages": "Populaire pagina's", "popular_pages": "Populaire pagina's",
"register_now": "Registreer nu", "register_now": "Registreer nu",
"register": "Registreer", "register": "Registreer",
@@ -231,7 +231,6 @@
"finish": "Voltooien", "finish": "Voltooien",
"few_sentences_about_yourself": "Een korte introductie over uzelf. Dit wordt weergegeven op uw persoonlijke pagina.", "few_sentences_about_yourself": "Een korte introductie over uzelf. Dit wordt weergegeven op uw persoonlijke pagina.",
"nearly_there": "Bijna klaar!", "nearly_there": "Bijna klaar!",
"nearly_there_instructions": "Tot slot, een korte beschrijving van u en een foto helpt u echt boekingen te krijgen en laat iedereen weten bij wie ze zijn geboekt.",
"set_availability_instructions": "Bepaal tijdbereiken waarin u periodiek beschikbaar bent. U kunt op een later tijdstip terugkomen en hier meer van aanmaken en toewijzen aan verschillende kalenders.", "set_availability_instructions": "Bepaal tijdbereiken waarin u periodiek beschikbaar bent. U kunt op een later tijdstip terugkomen en hier meer van aanmaken en toewijzen aan verschillende kalenders.",
"set_availability": "Beschikbaarheid bepalen", "set_availability": "Beschikbaarheid bepalen",
"continue_without_calendar": "Doorgaan zonder kalender", "continue_without_calendar": "Doorgaan zonder kalender",
@@ -1408,7 +1407,6 @@
"team_url_required": "Moet een team-URL invoeren", "team_url_required": "Moet een team-URL invoeren",
"team_url_taken": "Deze URL is al in gebruik", "team_url_taken": "Deze URL is al in gebruik",
"team_publish": "Team publiceren", "team_publish": "Team publiceren",
"number_sms_notifications": "Telefoonnummer (sms-meldingen)",
"attendee_email_variable": "E-mailadres deelnemer", "attendee_email_variable": "E-mailadres deelnemer",
"attendee_email_info": "Het e-mailadres van de persoon die boekt", "attendee_email_info": "Het e-mailadres van de persoon die boekt",
"kbar_search_placeholder": "Typ een opdracht of zoek...", "kbar_search_placeholder": "Typ een opdracht of zoek...",
Loaded 100 of 306 files, more files were not shown because too many files have changed in this diff. Show more