Compare commits
370 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14a9fdf78c | ||
|
|
7c6e394416 | ||
|
|
fe35cf6570 | ||
|
|
fdf7516cdd | ||
|
|
9733da67ae | ||
|
|
f0eed8ad30 | ||
|
|
aee2d0dbba | ||
|
|
19b3997ccd | ||
|
|
5044614983 | ||
|
|
b563bac1a7 | ||
|
|
aee5a406b7 | ||
|
|
5445ca5944 | ||
|
|
5f4bd87f0d | ||
|
|
79f9bf6d5e | ||
|
|
2f892a9ec5 | ||
|
|
691235f874 | ||
|
|
b7ad073de9 | ||
|
|
bcf40bbf26 | ||
|
|
b8e9275ceb | ||
|
|
01a6652f4d | ||
|
|
9a94cb386e | ||
|
|
a519206db7 | ||
|
|
90a22eda7d | ||
|
|
58ef1bbc36 | ||
|
|
a7875d071e | ||
|
|
04314f5e05 | ||
|
|
28d668ff38 | ||
|
|
92aaed5cc5 | ||
|
|
c5444c84fc | ||
|
|
63bd9a1202 | ||
|
|
6fe824088a | ||
|
|
2e5deae7c0 | ||
|
|
ec0ec5d308 | ||
|
|
86d2444d06 | ||
|
|
936378831e | ||
|
|
ac3e7ff072 | ||
|
|
5a6c6dc385 | ||
|
|
5f627ad963 | ||
|
|
dd656113ab | ||
|
|
e37ba3325b | ||
|
|
1d711dde65 | ||
|
|
c75893ce65 | ||
|
|
9f506e7635 | ||
|
|
6fee04d07c | ||
|
|
abce15ff0d | ||
|
|
8d3f0bf38e | ||
|
|
e5ec9357a9 | ||
|
|
855aa56e77 | ||
|
|
9aa53c1e0a | ||
|
|
f98c455915 | ||
|
|
e56e83b4a2 | ||
|
|
2234b7d5de | ||
|
|
5d6f94fce7 | ||
|
|
c711c80b8d | ||
|
|
e0e745f1ca | ||
|
|
0e43766b9c | ||
|
|
cee41eabc7 | ||
|
|
3d4de9476d | ||
|
|
fb20d24e8d | ||
|
|
d813b6ae54 | ||
|
|
1abb5f1ea5 | ||
|
|
830f033f9b | ||
|
|
cb14aaca14 | ||
|
|
20da74b4a6 | ||
|
|
038e8a4b7d | ||
|
|
2c2a97de73 | ||
|
|
c9b1f52382 | ||
|
|
0bc511a886 | ||
|
|
d0e047166e | ||
|
|
4c1b7ef03f | ||
|
|
5c0983ef6c | ||
|
|
66015cba39 | ||
|
|
516ade0af5 | ||
|
|
5d0ba3dafc | ||
|
|
798930bf23 | ||
|
|
55f1d727f8 | ||
|
|
aef6b70d8b | ||
|
|
0675ff8762 | ||
|
|
c4862c4b92 | ||
|
|
97fdfc5d6b | ||
|
|
712dceb8cb | ||
|
|
803e5c7f2d | ||
|
|
889edb8b44 | ||
|
|
898efbb280 | ||
|
|
7f5a2363f9 | ||
|
|
a41dd30467 | ||
|
|
b2fb60af31 | ||
|
|
51d553559f | ||
|
|
1e9234ea67 | ||
|
|
20d2955e68 | ||
|
|
38b41f0adb | ||
|
|
84f897e330 | ||
|
|
1976aa761c | ||
|
|
522875da74 | ||
|
|
447def5849 | ||
|
|
00a79bdaba | ||
|
|
890daffad0 | ||
|
|
476399abe8 | ||
|
|
ce3947ac4c | ||
|
|
2ec0673e3d | ||
|
|
7f8883866a | ||
|
|
5567721431 | ||
|
|
c201bfab2d | ||
|
|
4a13448595 | ||
|
|
fb38c062ae | ||
|
|
19d1744138 | ||
|
|
d14c7ed5c6 | ||
|
|
5c98eee647 | ||
|
|
42b1f090b0 | ||
|
|
df00df5124 | ||
|
|
34a75090c4 | ||
|
|
d0a6d6a6e6 | ||
|
|
ae5d5e1261 | ||
|
|
dedf001237 | ||
|
|
3bddb58fc2 | ||
|
|
cd208d29ab | ||
|
|
c0081b971b | ||
|
|
6ea2c47942 | ||
|
|
b202c7b595 | ||
|
|
656d319cd9 | ||
|
|
675340cb73 | ||
|
|
c709f9ed1b | ||
|
|
72d029d9f6 | ||
|
|
64db8d1cd4 | ||
|
|
acf8b83b1a | ||
|
|
6fb67bff20 | ||
|
|
7b65942de2 | ||
|
|
bf74fab0d3 | ||
|
|
91a73c8105 | ||
|
|
8ede48b1a8 | ||
|
|
f52e277dc4 | ||
|
|
8bb3e9c0be | ||
|
|
d9bb8aacfc | ||
|
|
60426aae74 | ||
|
|
c3da8a852f | ||
|
|
aa28cf0641 | ||
|
|
1d10874890 | ||
|
|
a81bb67cb1 | ||
|
|
de32c0c3ca | ||
|
|
b8dc26b9d3 | ||
|
|
faa295837c | ||
|
|
ff3569fdf8 | ||
|
|
12fa906031 | ||
|
|
509e0b0a39 | ||
|
|
811f4351a5 | ||
|
|
9dc45071c5 | ||
|
|
2079199bab | ||
|
|
f2095fb594 | ||
|
|
df0d4654fe | ||
|
|
b616d36fcc | ||
|
|
a8d2cf0b58 | ||
|
|
77ac5542dd | ||
|
|
2fbdb93efb | ||
|
|
07b75dadbd | ||
|
|
8d0861809c | ||
|
|
067a48093a | ||
|
|
1f0efb9aa4 | ||
|
|
e8ecab6456 | ||
|
|
2f5e7bcb8b | ||
|
|
af89de8004 | ||
|
|
1119d7f558 | ||
|
|
64f39b0d47 | ||
|
|
2a77f2c477 | ||
|
|
c720e4e960 | ||
|
|
1eac8a1aa3 | ||
|
|
e06edadda5 | ||
|
|
5aaf702e2b | ||
|
|
a9f9822091 | ||
|
|
73de0c2185 | ||
|
|
cad77ad237 | ||
|
|
c59dce1284 | ||
|
|
ba3034fd8d | ||
|
|
b4c96c96e6 | ||
|
|
ce4ed40ae0 | ||
|
|
c57debe600 | ||
|
|
8459f6d2b4 | ||
|
|
1bf4913051 | ||
|
|
d7bd1e9957 | ||
|
|
7baedc2f64 | ||
|
|
89bfff9a0b | ||
|
|
8de822500c | ||
|
|
8f6f34931b | ||
|
|
7737164bbf | ||
|
|
c91b46c9fb | ||
|
|
dabd82d018 | ||
|
|
9ac2843e9e | ||
|
|
b21dd3418b | ||
|
|
24182625bb | ||
|
|
e0a923979a | ||
|
|
745fadab2f | ||
|
|
c6e60bd706 | ||
|
|
118ee6bfb6 | ||
|
|
bfcd583376 | ||
|
|
116e6d0938 | ||
|
|
e52e1e3e23 | ||
|
|
b75e384a2d | ||
|
|
32dc258077 | ||
|
|
80ef94fb93 | ||
|
|
f371595ae0 | ||
|
|
97f971b8a5 | ||
|
|
038ea3365a | ||
|
|
2289c68979 | ||
|
|
103877737e | ||
|
|
55f25d9194 | ||
|
|
3e15459c20 | ||
|
|
460dda690d | ||
|
|
33694196e1 | ||
|
|
b5569c6b1c | ||
|
|
4e74c0e27f | ||
|
|
5e8a80001d | ||
|
|
9921b76da0 | ||
|
|
73f607f27a | ||
|
|
fac4de1144 | ||
|
|
e5f8437282 | ||
|
|
1a20b0a0c6 | ||
|
|
ffc0f460a0 | ||
|
|
c9c21e6a67 | ||
|
|
9c94aadbf7 | ||
|
|
f8c036164c | ||
|
|
67bcbfd75a | ||
|
|
54be2a2ec1 | ||
|
|
4608b9d56d | ||
|
|
8d9c69916b | ||
|
|
643e64a0e4 | ||
|
|
20404611b0 | ||
|
|
f7fda47534 | ||
|
|
c48d0d6c34 | ||
|
|
861cfdfed0 | ||
|
|
fbc1df9a30 | ||
|
|
ac6275b906 | ||
|
|
d2b9e67424 | ||
|
|
70683a89b9 | ||
|
|
59d4d92b52 | ||
|
|
8b68263800 | ||
|
|
7739994f4e | ||
|
|
a61cb690af | ||
|
|
e24d8889fc | ||
|
|
f0abf47ecc | ||
|
|
1c0c3c7690 | ||
|
|
09c4040ce5 | ||
|
|
57eeb48a8e | ||
|
|
84d75cf693 | ||
|
|
bf46038474 | ||
|
|
e93b7d942a | ||
|
|
6e7359ae96 | ||
|
|
bd2a795d7a | ||
|
|
8a70ea66e9 | ||
|
|
46df4c048e | ||
|
|
592dcd36b3 | ||
|
|
3bb76a3a62 | ||
|
|
4537117624 | ||
|
|
9b5da1bca3 | ||
|
|
80bd7fd89b | ||
|
|
a66610d9c2 | ||
|
|
4cd7a4ce5b | ||
|
|
baa7e868bd | ||
|
|
445faa406a | ||
|
|
4be4a01968 | ||
|
|
bc46f4fbc4 | ||
|
|
9b583694a3 | ||
|
|
81e2ae1352 | ||
|
|
3e1fe30186 | ||
|
|
f91ed7837c | ||
|
|
1567feb75e | ||
|
|
43a721dce6 | ||
|
|
0f82427b1e | ||
|
|
3e5987abec | ||
|
|
3761a75b28 | ||
|
|
9d7dc09974 | ||
|
|
bab72f1514 | ||
|
|
fbbd7ea45a | ||
|
|
7bc7b241ac | ||
|
|
0dd72888a9 | ||
|
|
a6382cf07f | ||
|
|
39761c520e | ||
|
|
c9a8bd369c | ||
|
|
d95e26d55c | ||
|
|
3bc659af44 | ||
|
|
cbf528c33e | ||
|
|
38f762f7b2 | ||
|
|
94a10992d2 | ||
|
|
26e1194ef3 | ||
|
|
21103580f7 | ||
|
|
ca405743fb | ||
|
|
6b426b5386 | ||
|
|
c0c4cb53db | ||
|
|
c21f0c2d49 | ||
|
|
4ce879e5dc | ||
|
|
25372b3c9e | ||
|
|
a3bd226347 | ||
|
|
e6f71c81bb | ||
|
|
972402be2c | ||
|
|
5c5d9d3406 | ||
|
|
c2a60657d4 | ||
|
|
d2965627d0 | ||
|
|
5deea2c5f6 | ||
|
|
7e6d56ca1f | ||
|
|
725a7ec0f4 | ||
|
|
ad8ffd3de4 | ||
|
|
8e447ea4b5 | ||
|
|
8bbfc0c7f0 | ||
|
|
2abd7779ac | ||
|
|
b6518b9ce1 | ||
|
|
43c939e342 | ||
|
|
357e279dd8 | ||
|
|
8afcba23c8 | ||
|
|
c359ebe85c | ||
|
|
3587e1ac9c | ||
|
|
3ff99f7877 | ||
|
|
c1d90eb438 | ||
|
|
5902f78fb2 | ||
|
|
8617b2db65 | ||
|
|
850497ea80 | ||
|
|
1890d5daf7 | ||
|
|
8d4b3c1c2c | ||
|
|
22a6d6ee3b | ||
|
|
05fa1feab0 | ||
|
|
bbf96a2e1d | ||
|
|
3b00bc7508 | ||
|
|
878c8b8248 | ||
|
|
23127318dc | ||
|
|
db7711869f | ||
|
|
ec2acedf34 | ||
|
|
d76ef4a007 | ||
|
|
c43e6783a7 | ||
|
|
91f2c380c5 | ||
|
|
b11d81fdd2 | ||
|
|
6792e17c80 | ||
|
|
dd446abeec | ||
|
|
c109ab1e30 | ||
|
|
dc13c95644 | ||
|
|
c85f0650fe | ||
|
|
7e6628e3ac | ||
|
|
e8af9110a7 | ||
|
|
ec9c8bb35d | ||
|
|
22aa083883 | ||
|
|
8c1b69cc0f | ||
|
|
8d1d3fcc7a | ||
|
|
dd48749f42 | ||
|
|
bd51316c68 | ||
|
|
2430784142 | ||
|
|
2b51cd9c8d | ||
|
|
de3c4aa75a | ||
|
|
813eaa83b7 | ||
|
|
ec2d0a89ba | ||
|
|
80a2b6c068 | ||
|
|
7faa9508c4 | ||
|
|
5773d064c2 | ||
|
|
0a7233d452 | ||
|
|
529f3027cd | ||
|
|
20cbab1c15 | ||
|
|
98d3cb1915 | ||
|
|
8322e5c8d1 | ||
|
|
36767afbf5 | ||
|
|
396355e350 | ||
|
|
da2c825dad | ||
|
|
dab146a313 | ||
|
|
712266664e | ||
|
|
f8781e4d5f | ||
|
|
d8b3c42c28 | ||
|
|
24e36ad46a | ||
|
|
644b0f1b0e | ||
|
|
deb97fdab0 | ||
|
|
58f55f84e2 | ||
|
|
5b3dd02747 | ||
|
|
ecc960f0a3 | ||
|
|
dfb1b5602d | ||
|
|
d6dd13a9d8 | ||
|
|
e0d1b6b5ea | ||
|
|
ffdf0b9217 |
72
.env.example
@@ -1,70 +1,2 @@
|
||||
# Set this value to 'agree' to accept our license:
|
||||
# LICENSE: https://github.com/calendso/calendso/blob/main/LICENSE
|
||||
#
|
||||
# Summary of terms:
|
||||
# - The codebase has to stay open source, whether it was modified or not
|
||||
# - You can not repackage or sell the codebase
|
||||
# - Acquire a commercial license to remove these terms by emailing: license@cal.com
|
||||
NEXT_PUBLIC_LICENSE_CONSENT=''
|
||||
|
||||
# DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>/<db-name>'
|
||||
DATABASE_URL="postgresql://postgres:@localhost:5432/calendso?schema=public"
|
||||
|
||||
GOOGLE_API_CREDENTIALS='secret'
|
||||
|
||||
BASE_URL='http://localhost:3000'
|
||||
NEXT_PUBLIC_APP_URL='http://localhost:3000'
|
||||
|
||||
JWT_SECRET='secret'
|
||||
|
||||
# @see: https://github.com/calendso/calendso/issues/263
|
||||
# Required for Vercel hosting - set NEXTAUTH_URL to equal your BASE_URL
|
||||
# NEXTAUTH_URL='http://localhost:3000'
|
||||
|
||||
# Remove this var if you don't want Cal to collect anonymous usage
|
||||
NEXT_PUBLIC_TELEMETRY_KEY=js.2pvs2bbpqq1zxna97wcml.oi2jzirnbj1ev4tc57c5r
|
||||
|
||||
# Used for the Office 365 / Outlook.com Calendar integration
|
||||
MS_GRAPH_CLIENT_ID=
|
||||
MS_GRAPH_CLIENT_SECRET=
|
||||
|
||||
# Used for the Zoom integration
|
||||
ZOOM_CLIENT_ID=
|
||||
ZOOM_CLIENT_SECRET=
|
||||
|
||||
#Used for the Daily integration
|
||||
DAILY_API_KEY=
|
||||
DAILY_SCALE_PLAN=''
|
||||
|
||||
# E-mail settings
|
||||
|
||||
# Cal uses nodemailer (@see https://nodemailer.com/about/) to provide email sending. As such we are trying to
|
||||
# allow access to the nodemailer transports from the .env file. E-mail templates are accessible within lib/emails/
|
||||
|
||||
# Configures the global From: header whilst sending emails.
|
||||
EMAIL_FROM='notifications@yourselfhostedcal.com'
|
||||
|
||||
# Configure SMTP settings (@see https://nodemailer.com/smtp/).
|
||||
# Note: The below configuration for Office 365 has been verified to work.
|
||||
EMAIL_SERVER_HOST='smtp.office365.com'
|
||||
EMAIL_SERVER_PORT=587
|
||||
EMAIL_SERVER_USER='<office365_emailAddress>'
|
||||
# Keep in mind that if you have 2FA enabled, you will need to provision an App Password.
|
||||
EMAIL_SERVER_PASSWORD='<office365_password>'
|
||||
# ApiKey for cronjobs
|
||||
CRON_API_KEY='0cc0e6c35519bba620c9360cfe3e68d0'
|
||||
|
||||
# Stripe Config
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY= # pk_test_...
|
||||
STRIPE_PRIVATE_KEY= # sk_test_...
|
||||
STRIPE_CLIENT_ID= # ca_...
|
||||
STRIPE_WEBHOOK_SECRET= # whsec_...
|
||||
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
|
||||
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
|
||||
|
||||
# Application Key for symmetric encryption and decryption
|
||||
# must be 32 bytes for AES256 encryption algorithm
|
||||
CALENDSO_ENCRYPTION_KEY=
|
||||
|
||||
# Intercom Config
|
||||
NEXT_PUBLIC_INTERCOM_APP_ID=
|
||||
# It now lives at `apps/web/.env.example`
|
||||
# DATABASE_URL got moved to `packages/prisma/.env.example`
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
node_modules
|
||||
packages/prisma/zod
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"modules": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"plugins": ["@typescript-eslint", "prettier", "react", "react-hooks"],
|
||||
"rules": {
|
||||
"prettier/prettier": ["error"],
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["playwright/**/*.{js,jsx,tsx,ts}"],
|
||||
"rules": {
|
||||
"no-undef": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-implicit-any": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest": true
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,12 +2,10 @@
|
||||
name: Feature request
|
||||
about: Suggest a feature or idea
|
||||
title: ""
|
||||
labels: enhancement
|
||||
labels: feature
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
> Please check if your Feature Request has not been already raised in the [Discussions Tab](https://github.com/calendso/calendso/discussions), as we would like to reduce duplicates. If it has been already raised, simply upvote it 🔼.
|
||||
|
||||
### Is your proposal related to a problem?
|
||||
|
||||
<!--
|
||||
|
||||
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
## What does this PR do?
|
||||
|
||||
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
<!-- Please delete options that are not relevant. -->
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
|
||||
## How should this be tested?
|
||||
|
||||
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
|
||||
|
||||
- [ ] Test A
|
||||
- [ ] Test B
|
||||
|
||||
## Checklist:
|
||||
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code and corrected any misspellings
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] New and existing unit tests pass locally with my changes
|
||||
71
.github/workflows/build.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: Build
|
||||
on: [push]
|
||||
jobs:
|
||||
build:
|
||||
name: Build on Node ${{ matrix.node }} and ${{ matrix.os }}
|
||||
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
NODE_ENV: test
|
||||
BASE_URL: http://localhost:3000
|
||||
JWT_SECRET: secret
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12.1
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: calendso
|
||||
ports:
|
||||
- 5432:5432
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
node: ["14.x"]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node ${{ matrix.node }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Install deps
|
||||
uses: bahmutov/npm-install@v1
|
||||
|
||||
- name: Next.js cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ github.workspace }}/.next/cache
|
||||
key: ${{ runner.os }}-nextjs
|
||||
|
||||
- run: yarn prisma migrate deploy
|
||||
- run: yarn test
|
||||
- run: yarn build
|
||||
|
||||
types:
|
||||
name: Check types
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node: ["14.x"]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node ${{ matrix.node }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Install deps
|
||||
uses: bahmutov/npm-install@v1
|
||||
|
||||
- run: yarn check-changed-files
|
||||
27
.github/workflows/check-types.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Check types
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
types:
|
||||
name: Check types
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node: ["14.x"]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node ${{ matrix.node }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: yarn
|
||||
- run: yarn type-check
|
||||
2
.github/workflows/crowdin.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: crowdin action
|
||||
uses: crowdin/github-action@1.4.0
|
||||
uses: crowdin/github-action@1.4.2
|
||||
with:
|
||||
upload_translations: true
|
||||
download_translations: true
|
||||
|
||||
61
.github/workflows/e2e.yml
vendored
@@ -1,18 +1,31 @@
|
||||
name: E2E test
|
||||
on: [push]
|
||||
on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- public/static/locales/**
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 10
|
||||
name: ${{ matrix.node }} and ${{ matrix.os }}
|
||||
|
||||
name: Testing ${{ matrix.node }} and ${{ matrix.os }}
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
BASE_URL: http://localhost:3000
|
||||
JWT_SECRET: secret
|
||||
GOOGLE_API_CREDENTIALS: "{}"
|
||||
# GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
PLAYWRIGHT_SECRET: ${{ secrets.CI_PLAYWRIGHT_SECRET }}
|
||||
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: true
|
||||
# CRON_API_KEY: xxx
|
||||
# CALENDSO_ENCRYPTION_KEY: xxx
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
PAYMENT_FEE_FIXED: 10
|
||||
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
SAML_ADMINS: pro@example.com
|
||||
# NEXTAUTH_URL: xxx
|
||||
# EMAIL_FROM: xxx
|
||||
# EMAIL_SERVER_HOST: xxx
|
||||
@@ -39,27 +52,26 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Use Node ${{ matrix.node }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
cache: "yarn"
|
||||
cache-dependency-path: yarn.lock
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Install deps
|
||||
uses: bahmutov/npm-install@v1
|
||||
- name: Next.js cache
|
||||
- name: Turbo Cache
|
||||
id: turbo-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ github.workspace }}/.next/cache
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-nextjs
|
||||
|
||||
- run: yarn test
|
||||
- run: yarn prisma migrate deploy
|
||||
- run: yarn db-seed
|
||||
- run: yarn build
|
||||
- run: yarn start &
|
||||
- run: npx wait-port 3000 --timeout 10000
|
||||
|
||||
path: .turbo
|
||||
key: turbo-${{ github.job }}-${{ github.event.pull_request.head.ref }}-${{ github.event.pull_request.head.sha }}
|
||||
restore-keys: |
|
||||
turbo-${{ github.job }}-${{ github.event.pull_request.head.ref }}-
|
||||
- run: yarn
|
||||
- name: Cache playwright binaries
|
||||
uses: actions/cache@v2
|
||||
id: playwright-cache
|
||||
@@ -69,11 +81,11 @@ jobs:
|
||||
~/.cache/ms-playwright
|
||||
**/node_modules/playwright
|
||||
key: cache-playwright-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install playwright deps
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: yarn playwright install-deps
|
||||
|
||||
- run: yarn test-playwright
|
||||
run: yarn playwright install --with-deps
|
||||
- run: yarn test-e2e
|
||||
|
||||
- name: Upload videos
|
||||
if: ${{ always() }}
|
||||
@@ -81,5 +93,8 @@ jobs:
|
||||
with:
|
||||
name: videos
|
||||
path: |
|
||||
test-results
|
||||
playwright/screenshots
|
||||
playwright/videos
|
||||
playwright/results
|
||||
playwright/reports
|
||||
|
||||
9
.github/workflows/lint.yml
vendored
@@ -1,5 +1,8 @@
|
||||
name: Lint
|
||||
on: [push]
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -10,12 +13,12 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
version: 14.x
|
||||
|
||||
- name: Install deps
|
||||
uses: bahmutov/npm-install@v1
|
||||
run: yarn
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
27
.gitignore
vendored
@@ -4,23 +4,23 @@
|
||||
.env
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
/.yarn
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
.nyc_output
|
||||
coverage
|
||||
/test-results/
|
||||
playwright/videos
|
||||
playwright/screenshots
|
||||
playwright/artifacts
|
||||
playwright/results
|
||||
playwright/reports/*
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
.next/
|
||||
out/
|
||||
build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
@@ -30,12 +30,15 @@ playwright/screenshots
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
@@ -54,3 +57,7 @@ yarn-error.log*
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Typescript
|
||||
tsconfig.tsbuildinfo
|
||||
# turbo
|
||||
.turbo
|
||||
@@ -13,3 +13,4 @@ public
|
||||
.prettierignore
|
||||
.DS_Store
|
||||
.eslintignore
|
||||
packages/prisma/zod
|
||||
|
||||
@@ -7,6 +7,7 @@ module.exports = {
|
||||
semi: true,
|
||||
printWidth: 110,
|
||||
arrowParens: "always",
|
||||
importOrder: ["^@ee/(.*)$", "^@lib/(.*)$", "^@components/(.*)$", "^@(server|trpc)/(.*)$", "^[./]"],
|
||||
importOrder: ["^@(calcom|ee)/(.*)$", "^@lib/(.*)$", "^@components/(.*)$", "^@(server|trpc)/(.*)$", "^[./]"],
|
||||
importOrderSeparation: true,
|
||||
plugins: [require("./merged-prettier-plugin")],
|
||||
};
|
||||
|
||||
6
.vscode/extensions.json
vendored
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"DavidAnson.vscode-markdownlint", // markdown linting
|
||||
"yzhang.markdown-all-in-one", // nicer markdown support
|
||||
"esbenp.prettier-vscode", // prettier plugin
|
||||
"dbaeumer.vscode-eslint", // eslint plugin
|
||||
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
|
||||
"heybourn.headwind", // automatically sort tailwind classes in predictable order, kinda like "prettier for tailwind",
|
||||
"stripe.vscode-stripe" // stripe VSCode extension
|
||||
"ban.spellright", // Spell check for docs
|
||||
"stripe.vscode-stripe", // stripe VSCode extension
|
||||
"Prisma.prisma" // syntax|format|completion for prisma
|
||||
]
|
||||
}
|
||||
|
||||
50
.vscode/launch.json
vendored
@@ -1,15 +1,39 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Next.js: Server",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js",
|
||||
"!**/node_modules/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"resolveSourceMapLocations": [
|
||||
"${workspaceFolder}/**",
|
||||
"!**/node_modules/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Next.js: Client",
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000"
|
||||
},
|
||||
{
|
||||
"name": "Next.js: Full Stack",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev",
|
||||
"console": "integratedTerminal",
|
||||
"serverReadyAction": {
|
||||
"pattern": "started server on .+, url: (https?://.+)",
|
||||
"uriFormat": "%s",
|
||||
"action": "debugWithChrome"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
.vscode/settings.json
vendored
@@ -6,8 +6,7 @@
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"eslint.run": "onSave",
|
||||
"workbench.colorCustomizations": {
|
||||
"titleBar.activeBackground": "#292929",
|
||||
"titleBar.inactiveBackground": "#888888"
|
||||
}
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"spellright.language": ["en"],
|
||||
"spellright.documentTypes": ["markdown"]
|
||||
}
|
||||
|
||||
4
LICENSE
@@ -2,7 +2,7 @@ Copyright (c) 2020-present Cal.com, Inc.
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
* All content that resides under "ee/" directory of this repository (Enterprise Edition) is licensed under the license defined in "ee/LICENSE".
|
||||
* All content that resides under "apps/web/ee/" (https://github.com/calcom/cal.com/tree/main/apps/web/ee) directory of this repository (Enterprise Edition) is licensed under the license defined in "ee/LICENSE".
|
||||
* All third party components incorporated into the Cal.com Software are licensed under the original license provided by the owner of the applicable component.
|
||||
* Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.
|
||||
|
||||
@@ -666,4 +666,4 @@ specific requirements.
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
172
README.md
@@ -1,8 +1,8 @@
|
||||
<!-- PROJECT LOGO -->
|
||||
<p align="center">
|
||||
<a href="https://github.com/calendso/calendso">
|
||||
<a href="https://github.com/calcom/cal.com">
|
||||
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
|
||||
|
||||
|
||||
</a>
|
||||
|
||||
<h3 align="center">Cal.com (formerly Calendso)</h3>
|
||||
@@ -17,20 +17,23 @@
|
||||
·
|
||||
<a href="https://cal.com">Website</a>
|
||||
·
|
||||
<a href="https://github.com/calendso/calendso/issues">Issues</a>
|
||||
<a href="https://github.com/calcom/cal.com/issues">Issues</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cal.com/slack"><img src="https://img.shields.io/badge/Slack-calendso.slack.com-%234A154B" alt="Join Cal.com Slack"></a>
|
||||
<a href="https://www.producthunt.com/posts/calendso"><img src="https://img.shields.io/badge/Product%20Hunt-%231%20Product%20of%20the%20Month-%23DA552E" alt="Product Hunt"></a>
|
||||
<a href="https://github.com/calendso/calendso/stargazers"><img src="https://img.shields.io/github/stars/calendso/calendso" alt="Github Stars"></a>
|
||||
<a href="https://github.com/calcom/cal.com/stargazers"><img src="https://img.shields.io/github/stars/calcom/cal.com" alt="Github Stars"></a>
|
||||
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
|
||||
<a href="https://github.com/calendso/calendso/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
|
||||
<img src="https://img.shields.io/github/package-json/v/calendso/calendso">
|
||||
<a href="https://github.com/calendso/calendso/pulse"><img src="https://img.shields.io/github/commit-activity/m/calendso/calendso" alt="Commits-per-month"></a>
|
||||
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-%2412%2Fmonth-brightgreen" alt="Pricing"></a>
|
||||
<a href="https://cal.crowdin.com/Cal"><img src="https://badges.crowdin.net/e/5a55420475b48696779e30e0208a1899/localized.svg" alt="Translate Slack"></a>
|
||||
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
|
||||
<a href="https://github.com/calcom/cal.com/pulse"><img src="https://img.shields.io/github/commit-activity/m/calcom/cal.com" alt="Commits-per-month"></a>
|
||||
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-%2412%2Fmonth-brightgreen" alt="Pricing"></a>
|
||||
<a href="https://jitsu.com?utm_source=github/calcom/cal.com"><img src="https://img.shields.io/badge/Metrics_tracked_by-JITSU-AA00FF?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgBrZDRCYAwDEQv6gCOoKO4hOCXI9QVnEZwiY5iF5GaVClaBNtioCSUvCR3tMJaxIfZgW4AGUoEPVwgPZoS0Dmgg3NBVDFNbMIsmYCak3J1jDk9iCQvsKJvkzr71N81Gj6vDT/LU2P6RhY63jcafk3YJEbgeZpiFyc/5HJKv8Ef273NSfABGbQfUZhnOSAAAAAASUVORK5CYII=" alt="Jitsu Tracked"></a>
|
||||
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
|
||||
<a href="https://twitter.com/calcom"><img src="https://img.shields.io/twitter/follow/calcom?style=social"></a>
|
||||
<a href="https://calendso.slack.com/archives/C02BY67GMMW"><img src="https://img.shields.io/badge/translations-contribute-brightgreen" /></a>
|
||||
|
||||
</p>
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
@@ -39,7 +42,7 @@
|
||||
|
||||
<img width="100%" alt="booking-screen" src="https://user-images.githubusercontent.com/8019099/134363898-4b29e18f-3e61-42b7-95bc-10891056249d.gif">
|
||||
|
||||
# Scheduling infrastructure for absolutely everyone.
|
||||
# Scheduling infrastructure for absolutely everyone
|
||||
|
||||
The open source Calendly alternative. You are in charge
|
||||
of your own data, workflow and appearance.
|
||||
@@ -48,7 +51,7 @@ Calendly and other scheduling tools are awesome. It made our lives massively eas
|
||||
|
||||
That's where Cal.com comes in. Self-hosted or hosted by us. White-label by design. API-driven and ready to be deployed on your own domain. Full control of your events and data.
|
||||
|
||||
### Product of the Month: April
|
||||
## Product of the Month: April
|
||||
|
||||
#### Support us on [Product Hunt](https://www.producthunt.com/posts/calendso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-calendso)
|
||||
|
||||
@@ -81,43 +84,56 @@ Here is what you need to be able to run Cal.
|
||||
- PostgreSQL
|
||||
- Yarn _(recommended)_
|
||||
|
||||
You will also need Google API credentials. You can get this from the [Google API Console](https://console.cloud.google.com/apis/dashboard). More details on this can be found below under the [Obtaining the Google API Credentials section](#Obtaining-the-Google-API-Credentials).
|
||||
> If you want to enable any of the available integrations, you may want to obtain additional credentials for each one. More details on this can be found below under the [integrations section](#integrations).
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone the repo
|
||||
|
||||
```sh
|
||||
git clone https://github.com/calcom/cal.com.git
|
||||
```
|
||||
|
||||
1. Go to the project folder
|
||||
|
||||
```sh
|
||||
cd cal.com
|
||||
```
|
||||
|
||||
1. Copy `apps/web/.env.example` to `apps/web/.env`
|
||||
|
||||
```sh
|
||||
cp apps/web/.env.example apps/web/.env
|
||||
cp packages/prisma/.env.example packages/prisma/.env
|
||||
```
|
||||
|
||||
1. Install packages with yarn
|
||||
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
|
||||
#### Quick start with `yarn dx`
|
||||
|
||||
> - **Requires Docker to be installed**
|
||||
> - **Requires Docker and Docker Compose to be installed**
|
||||
> - Will start a local Postgres instance with a few test users - the credentials will be logged in the console
|
||||
|
||||
```bash
|
||||
git clone git@github.com:calendso/calendso.git
|
||||
cd calendso
|
||||
yarn
|
||||
```sh
|
||||
yarn dx
|
||||
```
|
||||
|
||||
#### Manual
|
||||
#### Manual setup
|
||||
|
||||
1. Clone the repo
|
||||
```sh
|
||||
git clone https://github.com/calendso/calendso.git
|
||||
```
|
||||
2. Install packages with yarn
|
||||
```sh
|
||||
yarn install
|
||||
```
|
||||
3. Copy `.env.example` to `.env`
|
||||
4. Configure environment variables in the .env file. Replace `<user>`, `<pass>`, `<db-host>`, `<db-port>` with their applicable values
|
||||
1. Configure environment variables in the .env file. Replace `<user>`, `<pass>`, `<db-host>`, `<db-port>` with their applicable values
|
||||
|
||||
```
|
||||
DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>'
|
||||
GOOGLE_API_CREDENTIALS='secret'
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>If you don't know how to configure the DATABASE_URL, then follow the steps here</summary>
|
||||
<summary>If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick DB using Heroku</summary>
|
||||
|
||||
1. Create a free account with [Heroku](https://www.heroku.com/).
|
||||
|
||||
@@ -143,43 +159,57 @@ yarn dx
|
||||
8. To view your DB, once you add new data in Prisma, you can use [Heroku Data Explorer](https://heroku-data-explorer.herokuapp.com/).
|
||||
</details>
|
||||
|
||||
5. Set up the database using the Prisma schema (found in `prisma/schema.prisma`)
|
||||
1. Set a 32 character random string in your .env file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one).
|
||||
1. Set up the database using the Prisma schema (found in `apps/web/prisma/schema.prisma`)
|
||||
|
||||
```sh
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
6. Run (in development mode)
|
||||
|
||||
1. Run (in development mode)
|
||||
|
||||
```sh
|
||||
yarn dev
|
||||
```
|
||||
7. Open [Prisma Studio](https://www.prisma.io/studio) to look at or modify the database content:
|
||||
yarn dev --scope=@calcom/web
|
||||
```
|
||||
|
||||
#### Setting up your first user
|
||||
|
||||
1. Open [Prisma Studio](https://www.prisma.io/studio) to look at or modify the database content:
|
||||
|
||||
```sh
|
||||
npx prisma studio
|
||||
```
|
||||
8. Click on the `User` model to add a new user record.
|
||||
9. Fill out the fields (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
|
||||
10. Open a browser to [http://localhost:3000](http://localhost:3000) and login with your just created, first user.
|
||||
11. Set a 32 character random string in your .env file for the CALENDSO_ENCRYPTION_KEY.
|
||||
|
||||
1. Click on the `User` model to add a new user record.
|
||||
1. Fill out the fields `email`, `username`, `password`, and set `metadata` to empty `{}` (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
|
||||
> New users are set on a `TRIAL` plan by default. You might want to adjust this behavior to your needs in the `prisma/schema.prisma` file.
|
||||
1. Open a browser to [http://localhost:3000](http://localhost:3000) and login with your just created, first user.
|
||||
|
||||
### E2E-Testing
|
||||
|
||||
```bash
|
||||
```sh
|
||||
# In first terminal
|
||||
yarn dx
|
||||
# In second terminal
|
||||
yarn test-playwright
|
||||
yarn workspace @calcom/web test-e2e
|
||||
|
||||
# To open last HTML report run:
|
||||
yarn workspace @calcom/web playwright-report
|
||||
```
|
||||
|
||||
### Upgrading from earlier versions
|
||||
|
||||
1. Pull the current version:
|
||||
```
|
||||
|
||||
```sh
|
||||
git pull
|
||||
```
|
||||
|
||||
2. Apply database migrations by running <b>one of</b> the following commands:
|
||||
|
||||
In a development environment, run:
|
||||
|
||||
```
|
||||
```sh
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
@@ -187,7 +217,7 @@ yarn test-playwright
|
||||
|
||||
In a production environment, run:
|
||||
|
||||
```
|
||||
```sh
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
@@ -201,14 +231,18 @@ yarn test-playwright
|
||||
```
|
||||
|
||||
4. Start the server. In a development environment, just do:
|
||||
|
||||
```sh
|
||||
yarn dev --scope=@calcom/web
|
||||
```
|
||||
yarn dev
|
||||
```
|
||||
|
||||
For a production build, run for example:
|
||||
|
||||
```sh
|
||||
yarn build --scope=@calcom/web
|
||||
yarn start --scope=@calcom/web
|
||||
```
|
||||
yarn build
|
||||
yarn start
|
||||
```
|
||||
|
||||
5. Enjoy the new version.
|
||||
<!-- DEPLOYMENT -->
|
||||
|
||||
@@ -217,11 +251,16 @@ yarn test-playwright
|
||||
### Docker
|
||||
|
||||
The Docker configuration for Cal is an effort powered by people within the community. Cal.com, Inc. does not provide official support for Docker, but we will accept fixes and documentation. Use at your own risk.
|
||||
|
||||
If you want to contribute to the Docker repository, [reply here](https://github.com/calendso/docker/discussions/32).
|
||||
|
||||
The Docker configuration can be found [in our docker repository](https://github.com/calendso/docker).
|
||||
|
||||
If you want to contribute to the Docker repository, [reply here](https://github.com/calcom/docker/discussions/32).
|
||||
|
||||
The Docker configuration can be found [in our docker repository](https://github.com/calcom/docker).
|
||||
|
||||
### Heroku
|
||||
|
||||
<a href="https://heroku.com/deploy?template=https://github.com/calcom/cal.com">
|
||||
<img width="185px" height="auto" src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
|
||||
</a>
|
||||
|
||||
### Railway
|
||||
|
||||
@@ -233,7 +272,7 @@ You can deploy Cal on [Railway](https://railway.app/) using the button above. Th
|
||||
|
||||
## Roadmap
|
||||
|
||||
See the [open issues](https://github.com/calendso/calendso/issues) for a list of proposed features (and known issues).
|
||||
See the [open issues](https://github.com/calcom/cal.com/issues) for a list of proposed features (and known issues).
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
|
||||
@@ -248,7 +287,9 @@ Contributions are what make the open source community such an amazing place to b
|
||||
5. Push to the branch (`git push origin feature/AmazingFeature`)
|
||||
6. Open a pull request
|
||||
|
||||
## Obtaining the Google API Credentials
|
||||
## Integrations
|
||||
|
||||
### Obtaining the Google API Credentials
|
||||
|
||||
1. Open [Google API Console](https://console.cloud.google.com/apis/dashboard). If you don't have a project in your Google Cloud subscription, you'll need to create one before proceeding further. Under Dashboard pane, select Enable APIS and Services.
|
||||
2. In the search box, type calendar and select the Google Calendar API search result.
|
||||
@@ -262,16 +303,16 @@ Contributions are what make the open source community such an amazing place to b
|
||||
10. The key will be created and you will be redirected back to the Credentials page. Select the newly generated client ID under OAuth 2.0 Client IDs.
|
||||
11. Select Download JSON. Copy the contents of this file and paste the entire JSON string in the .env file as the value for GOOGLE_API_CREDENTIALS key.
|
||||
|
||||
## Obtaining Microsoft Graph Client ID and Secret
|
||||
### Obtaining Microsoft Graph Client ID and Secret
|
||||
|
||||
1. Open [Azure App Registration](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and select New registration
|
||||
2. Name your application
|
||||
3. Set **Who can use this application or access this API?** to **Accounts in any organizational directory (Any Azure AD directory - Multitenant)**
|
||||
4. Set the **Web** redirect URI to `<Cal.com URL>/api/integrations/office365calendar/callback` replacing Cal.com URL with the URI at which your application runs.
|
||||
5. Use **Application (client) ID** as the **MS_GRAPH_CLIENT_ID** attribute value in .env
|
||||
6. Click **Certificates & secrets** create a new client secret and use the value as the **MS_GRAPH_CLIENT_SECRET** attriubte
|
||||
6. Click **Certificates & secrets** create a new client secret and use the value as the **MS_GRAPH_CLIENT_SECRET** attribute
|
||||
|
||||
## Obtaining Zoom Client ID and Secret
|
||||
### Obtaining Zoom Client ID and Secret
|
||||
|
||||
1. Open [Zoom Marketplace](https://marketplace.zoom.us/) and sign in with your Zoom account.
|
||||
2. On the upper right, click "Develop" => "Build App".
|
||||
@@ -287,13 +328,12 @@ Contributions are what make the open source community such an amazing place to b
|
||||
12. Click "Done".
|
||||
13. You're good to go. Now you can easily add your Zoom integration in the Cal.com settings.
|
||||
|
||||
## Obtaining Daily API Credentials
|
||||
### Obtaining Daily API Credentials
|
||||
|
||||
1. Open [Daily](https://www.daily.co/) and sign into your account.
|
||||
2. From within your dashboard, go to the [developers](https://dashboard.daily.co/developers) tab.
|
||||
3. Copy your API key.
|
||||
4. Now paste the API key to your .env file into the `DAILY_API_KEY` field in your .env file.
|
||||
5. If you have a [Daily Scale Plan](https://www.daily.co/pricing) can also enable the ability to record Daily video meetings. To do so, set the `DAILY_SCALE_PLAN` environment variable to `'true'`
|
||||
1. Open [Daily](https://www.daily.co/) and sign into your account.
|
||||
2. From within your dashboard, go to the [developers](https://dashboard.daily.co/developers) tab.
|
||||
3. Copy your API key.
|
||||
4. Now paste the API key to your .env file into the `DAILY_API_KEY` field in your .env file.
|
||||
|
||||
<!-- LICENSE -->
|
||||
|
||||
@@ -314,3 +354,7 @@ Special thanks to these amazing projects which help power Cal.com:
|
||||
- [Day.js](https://day.js.org/)
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
- [Prisma](https://prisma.io/)
|
||||
|
||||
[<img src="https://jitsu.com/img/powered-by-jitsu.png?gh=true">](https://jitsu.com/?utm_source=cal.com-gihub)
|
||||
|
||||
Cal.com is an [open startup](https://jitsu.com) and [Jitsu](https://github.com/jitsucom/jitsu) (an open-source Segment alternative) helps us to track most of the usage metrics.
|
||||
|
||||
26
app.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "Cal.com",
|
||||
"description": "Open Source Scheduling",
|
||||
"repository": "https://github.com/calcom/cal.com",
|
||||
"logo": "https://cal.com/android-chrome-512x512.png",
|
||||
"keywords": ["react", "typescript", "node", "nextjs", "prisma", "postgres", "trpc"],
|
||||
"addons": [
|
||||
{
|
||||
"plan": "heroku-postgresql:hobby-dev"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"BASE_URL": {
|
||||
"description": "Replace HEROKU_APP_NAME with the name given to your app",
|
||||
"value": "https://HEROKU_APP_NAME.herokuapp.com"
|
||||
},
|
||||
"CALENDSO_ENCRYPTION_KEY": {
|
||||
"description": "Application Key for symmetric encryption and decryption. Must be 32 bytes for AES256 encryption algorithm.",
|
||||
"value": "secret"
|
||||
},
|
||||
"JWT_SECRET": "secret"
|
||||
},
|
||||
"scripts": {
|
||||
"postdeploy": "cd apps/web && npx prisma migrate deploy"
|
||||
}
|
||||
}
|
||||
1
apps/docs/.eslintrc.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("@calcom/config/eslint-preset");
|
||||
7
apps/docs/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
.next
|
||||
.DS_Store
|
||||
yarn-error.log
|
||||
dist
|
||||
examples
|
||||
packages
|
||||
1
apps/docs/.nvmrc
Normal file
@@ -0,0 +1 @@
|
||||
14.17
|
||||
2
apps/docs/.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.next
|
||||
node_modules
|
||||
21
apps/docs/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Shu Ding
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
81
apps/docs/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
<!-- PROJECT LOGO -->
|
||||
<div align="right">
|
||||
<a href="https://github.com/calcom/cal.com">
|
||||
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
|
||||
</a>
|
||||
<a href="https://cal.com">Website</a>
|
||||
·
|
||||
<a href="https://github.com/calcom/docs/issues">Community Support</a>
|
||||
</div>
|
||||
|
||||
# Cal.com Documentation
|
||||
|
||||
The official product, support and developer documentation, containing information and guides about using the product as well as support for self-hosted installations. This documentation site runs on [Nextra](https://nextra.vercel.app), so you may refer to their documentation should you need information on anything that isn't covered here.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git
|
||||
- Node.js & npm
|
||||
- Yarn
|
||||
|
||||
## Installation
|
||||
|
||||
Firstly, clone the repository using Git:
|
||||
|
||||
```console
|
||||
git clone https://github.com/calcom/docs.git
|
||||
```
|
||||
|
||||
Now, you can install the dependencies with yarn:
|
||||
|
||||
```console
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Editing
|
||||
|
||||
To create, edit and delete documentation pages, you can simply create markdown (.mdx) files in the `pages/` folder. You can edit Markdown with any text editor, but VS Code and WebStorm have side-by-side previews so you can see your formatted content whilst writing markdown.
|
||||
|
||||
You will also need to add it as an entry to the `meta.json` file found in whichever directory that the .mdx file is in.
|
||||
|
||||
## Local Development
|
||||
|
||||
```console
|
||||
yarn dev
|
||||
```
|
||||
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
|
||||
## Build
|
||||
|
||||
```console
|
||||
yarn build
|
||||
```
|
||||
|
||||
This command generates static content into the `build` directory and can be served using any static content hosting service.
|
||||
|
||||
## How to easily contribute
|
||||
|
||||
## Existing Page
|
||||
|
||||
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
|
||||
2. From here you can view all current pages on the documentation site. Select the page you would like to contribute to.
|
||||
3. You should now be able to view the page you have selected. Located at the top right of the page will be a pencil icon. Pressing this will bring you up an editor to edit and make changes. You can add formatting using the buttons at the top, which will automatically insert the relevant markdown content needed to style the text.
|
||||
4. From here make the changes you wish to make.
|
||||
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
|
||||
6. Your changes have been saved, to submit them for review, located on your screen, press the green 'Create Pull Request' button.
|
||||
7. Fill in all the relevant details such as title and description and after finalize the submission.
|
||||
|
||||
You have now successfully edited and submitted changes to our documentation site.
|
||||
|
||||
## Creating a New Page
|
||||
|
||||
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
|
||||
2. From here you can view all current pages on the documentation site. At the top of your screen press the 'New file' button.
|
||||
3. You should now be able to view the page you have created. Remember when renaming the document to put .mdx at the end of the file name.
|
||||
4. From here make the changes you wish to make. Such as creating a title, sub-title and body text.
|
||||
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
|
||||
6. Your changes have been saved, to submit them for review, located on your screen, press the greem 'Create Pull Request' button.
|
||||
7. Fill in all the relevant details such as title and description and after finalize the submission.
|
||||
|
||||
You have now successfully created and submitted changes to our documentation site.
|
||||
7
apps/docs/next.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const withNextra = require("nextra")({
|
||||
theme: "nextra-theme-docs",
|
||||
themeConfig: "./theme.config.js",
|
||||
unstable_staticImage: true,
|
||||
});
|
||||
module.exports = withNextra();
|
||||
20
apps/docs/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@calcom/docs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"start": "next start",
|
||||
"build": "next build"
|
||||
},
|
||||
"author": "Cal.com, Inc.",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"next": "^12.0.9",
|
||||
"nextra": "^1.1.0",
|
||||
"nextra-theme-docs": "^1.2.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
}
|
||||
}
|
||||
6
apps/docs/pages/_app.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import "nextra-theme-docs/style.css";
|
||||
import "./style.css";
|
||||
|
||||
export default function Nextra({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
23
apps/docs/pages/availability.mdx
Normal file
@@ -0,0 +1,23 @@
|
||||
# Availability
|
||||
|
||||
## Setting your availability
|
||||
|
||||
1. Go to [Your Availability](https://app.cal.com/availability) page within your cal.com account.
|
||||
2. On the availability page you can manage your availability to suit your working day accordingly.
|
||||
You can also troubleshoot your availability if your calendar does not look like it is blocking out the correct times.
|
||||
|
||||
|
||||
## Troubleshooting availability
|
||||
|
||||
This will tell you when your calendar shows you as busy, so you can understand why Cal is blocking certain times.
|
||||
|
||||
## How to troubleshoot availability
|
||||
|
||||
1. Go to [Your Availability](https://app.cal.com/availability).
|
||||
2. To the right of your screen a box saying 'Something doesn't look right?' will appear. Press the button 'Launch Troubleshooter'.
|
||||
3. After pressing this, your availability will appear according to your calendar and inform you of the times booked up for that day!
|
||||
|
||||
By doing this you will know understand why certain times are available and others are blocked.
|
||||
|
||||
## In team settings availability set to only Mondays but the calendar shows availability on other days as well
|
||||
It’s showing as available on days other than Monday because only you have set your availability to only Mondays, whereas the rest of the team haven't made that setting.
|
||||
33
apps/docs/pages/billing.mdx
Normal file
@@ -0,0 +1,33 @@
|
||||
# Billing
|
||||
## How the trial works
|
||||
You are given FREE access for 14 days of our PRO subscription, you can use this to test and try out our product and see if it works for you. No credit card is required to sign up and you decide if you want to upgrade to a PRO subscription afterwards.
|
||||
|
||||
## How to cancel the trial
|
||||
If you are looking to cancel the trial and want to downgrade to the free option you can contact our support team where we will be happy to help you make that change!
|
||||
|
||||
## How to upgrade
|
||||
If you are looking at upgrading from our FREE subscription to our PRO subscription, head over to cal.com/upgrade where you can easily upgrade hassle free.
|
||||
|
||||
## How to downgrade
|
||||
1. Go to your [Billing Settings](https://app.cal.com/settings/billing).
|
||||
2. From here you can press the button called `Go to the billing Portal`. That will take you to the page where you can upgrade/downgrade your plan.
|
||||
|
||||
## How to delete your account
|
||||
You can delete your account from within the [Settings](https://app.cal.com/settings/profile) option. Just scroll all the way down and click on `Delete Account`.
|
||||
|
||||
## Purchasing a premium username
|
||||
We've reserved a ton of premium usernames, such as short handles or first names to prevent name squatters. To find out if your username is premium, head over to [cal.com/signup](https://cal.com/signup) and choose your desired username. From here you will be taken straight to checkout and after proceeding your Cal.com account will be created with your desired username.
|
||||
|
||||
## Manage your subscription
|
||||
1. Go to your [Billing Settings](https://app.cal.com/settings/billing).
|
||||
2. From here you can press the button called `Go to the billing Portal`.
|
||||
3. This will take you to an external site provided by Stripe as they deal with all our payments.
|
||||
|
||||
Some users may not be able to access Billing as their billing email is different to their account email. If this is the case, you can change the email associated with your account in [Profile Settings](https://app.cal.com/settings/profile).
|
||||
|
||||
## Subscription for each team member
|
||||
If your team requires multiple event types then each team member has to be subscribed to our paid plan. If that is something that isn’t necessary for your team, you can proceed with your FREE plan.
|
||||
|
||||
## Discount for non-profits and students
|
||||
We offer 50% for non-profit organizations and students. Just raise a ticket with our support team and submit the necessary proof of status.
|
||||
|
||||
25
apps/docs/pages/bookings.mdx
Normal file
@@ -0,0 +1,25 @@
|
||||
# Bookings
|
||||
|
||||
## What can you do on the bookings page?
|
||||
|
||||
On the bookings page you are able to see upcoming and past events booked through your event type links. This page also lets you cancel or reschedule upcoming events users have scheduled.
|
||||
|
||||
## How to view bookings
|
||||
|
||||
1. Go to [your upcoming and past bookings](https://app.cal.com/bookings/upcoming).
|
||||
2. On this page you can see upcoming and past events booked through your event type links.
|
||||
|
||||
## Reschedule bookings
|
||||
|
||||
1. Go to [your rescheduled bookings](https://app.cal.com/bookings/upcoming).
|
||||
2. Hovering over the event you want to reschedule, click the button saying 'Reschedule'
|
||||
3. Clicking 'Reschedule' will bring you to your Cal booking page. Select a new Time and Date.
|
||||
4. After selecting this you can go ahead and click that 'Reschedule' Button!
|
||||
5. After, you and your attendee will receive a new confirmation email of your new date and time.
|
||||
|
||||
## Cancel bookings
|
||||
|
||||
1. Go to [your cancelled](https://app.cal.com/bookings/cancelled).
|
||||
2. Hovering over the event you want to cancel, click the button saying 'Cancel'
|
||||
3. Once done, you will receive a confirmation message saying 'Really cancel your booking?'. After confirming you can go ahead and click the red 'Cancel' button at the bottom of your screen.
|
||||
4. After, you and your attendee will receive a new confirmation email of your event being cancelled.
|
||||
33
apps/docs/pages/developer/adding-css.mdx
Normal file
@@ -0,0 +1,33 @@
|
||||
import Callout from 'nextra-theme-docs/callout';
|
||||
|
||||
# Adding CSS
|
||||
|
||||
<Callout>
|
||||
Adding or modifying CSS counts as changing the code, so as per [our license](https://github.com/calcom/cal.com/blob/main/LICENSE) you must either open-source your modified version or purchase an enterprise license.
|
||||
</Callout>
|
||||
|
||||
Cal.com uses [TailwindCSS](https://tailwindcss.com) as a replacement for traditional CSS styling within the application, but some people prefer to add CSS styles themselves.
|
||||
|
||||
CSS files should be stored in the `styles` directory within the codebase.
|
||||
|
||||
Within the `styles` directory, you will find two CSS files, `fonts.css` and `global.css`. We suggest not to add to these files, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
|
||||
|
||||
## Adding new stylesheets
|
||||
Firstly, create the CSS file inside the `styles` directory.
|
||||
|
||||
Then, open the `pages/_app.tsx` file, and you will see the following two lines:
|
||||
```javascript
|
||||
import "../styles/fonts.css";
|
||||
import "../styles/globals.css";
|
||||
```
|
||||
|
||||
Duplicate one of these import statements and change the path to link to your new CSS stylesheet, like so:
|
||||
```javascript
|
||||
import "../styles/your-new-stylesheet.css";
|
||||
```
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
These styles will apply to all pages and components in your application.
|
||||
</Callout>
|
||||
|
||||
Due to the global nature of stylesheets, and to avoid conflicts, you may **only import them inside `pages/_app.tsx`**.
|
||||
15
apps/docs/pages/developer/code-styling.mdx
Normal file
@@ -0,0 +1,15 @@
|
||||
# Code Styling
|
||||
Keeping our code styles consistent is key to making the repository easy to read and work with.
|
||||
|
||||
We use a number of style guides written by other amazing companies, simply because they are widely used and because we like working with them.
|
||||
|
||||
We don't expect you to study every single rule of each style guide, but these are great reference points as to how your code should be styled. We may reject a pull request if your code style significantly differs from these style guides however.
|
||||
|
||||
## ESLint & Prettier
|
||||
Calendso uses the ESLint and Prettier formatting tools, and the repository comes with defined rules for each tool. We recommend setting up both tools and using these to help automatically style your code to our guidelines.
|
||||
|
||||
## JavaScript/TypeScript
|
||||
We use the [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) for all JavaScript and Typescript code.
|
||||
|
||||
## HTML & CSS
|
||||
We use the [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html) for any HTML and CSS markup. However, exceptions to the HTML guide apply where JSX differentiates from standard HTML.
|
||||
9
apps/docs/pages/developer/meta.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"migrations": "Migrations",
|
||||
"pre-fill": "Pre-fill fields",
|
||||
"code-styling": "Code styling",
|
||||
"project-structure": "Project structure",
|
||||
"pull-requests": "Pull requests",
|
||||
"adding-css": "Adding CSS"
|
||||
}
|
||||
|
||||
37
apps/docs/pages/developer/migrations.mdx
Normal file
@@ -0,0 +1,37 @@
|
||||
# Database Migrations
|
||||
As described in the [upgrade guide](https://docs.cal.com/self-hosting/upgrading.md), you should use the `npx prisma migrate dev` or `npx prisma migrate deploy` command to update the database.
|
||||
|
||||
We use database migrations in order to handle changes to the database schema in a more secure and stable way. This is actually very common. The thing is that when just changing the schema in `schema.prisma` without creating migrations, the update to the newer database schema can damage or delete all data in production mode, since the system sometimes doesn't know how to transform the data from A to B. Using migrations, each step is reproducable, transparent and can be undone in a simple way.
|
||||
|
||||
## Creating migrations
|
||||
If you are modifying the codebase and make a change to the `schema.prisma` file, you must create a migration.
|
||||
|
||||
To create a migration for your previously changed `schema.prisma`, simply run the following:
|
||||
```
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
Now, you must create a short name for your migration to describe what changed (for example, "user_add_email_verified"). Then just add and commit it with the corresponding code that uses your new database schema.
|
||||
|
||||
:::caution
|
||||
|
||||
Always keep an eye on what migrations Prisma is generating. Prisma often happily will drop entire columns of data because it can't figure out what to do.
|
||||
|
||||
:::
|
||||
|
||||
## Error: The database schema is not empty
|
||||
Prisma uses a database called `_prisma_migrations` to keep track of which migrations have been applied and which haven't. If your local migrations database doesn't match up with what's in the actual database, then Prisma will throw the following error:
|
||||
```
|
||||
Error: P3005
|
||||
|
||||
The database schema for `localhost:5432` is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline
|
||||
```
|
||||
|
||||
In order to fix this, we need to tell Prisma which migrations have already been applied.
|
||||
|
||||
This can be done by running the following command, replacing `migration_name` with each migration that you have already applied:
|
||||
```
|
||||
npx prisma migrate resolve --applied migration_name
|
||||
```
|
||||
|
||||
You will need to run the command for each migration that you want to mark as applied.
|
||||
20
apps/docs/pages/developer/pre-fill.mdx
Normal file
@@ -0,0 +1,20 @@
|
||||
# Pre-fill fields
|
||||
|
||||
You can pre-fill a number of fields on the booking form by using their corresponding URL parameters. This can include the user’s name, email, or guests to be added to the booking.
|
||||
|
||||
Usually when they go to the link, all that is needed will be the time of the booking, and the form will be pre-filled with the information given.
|
||||
|
||||
Pre-filling booking fields can save a lot of time and speed up processes with filling out these forms, and assist with a smooth integration with your existing website or app.
|
||||
|
||||
You can pre-fill a user’s name and email address like so:
|
||||
```text
|
||||
cal.com/rick/quick-chat/?email=attendee@example.com&name=John
|
||||
```
|
||||
The data is persisted through the 3 booking pages; and is used to prefill the booking form.
|
||||
|
||||
Guests can also be added to the link, there is also no limit to the amount of guests you wish to add.
|
||||
|
||||
These should be added to your link like this:
|
||||
```text
|
||||
guest=guest1@example.com&guest=guest2@example.com
|
||||
```
|
||||
46
apps/docs/pages/developer/project-structure.mdx
Normal file
@@ -0,0 +1,46 @@
|
||||
# Project Structure
|
||||
|
||||
This page gives an overview of how the codebase is structured so you can easily dive into the Cal.com code.
|
||||
|
||||
Cal.com is written in Next.js, so you will find that we follow Next.js best practices for structure and layouts.
|
||||
|
||||
## Basic folder structure
|
||||
|
||||
The project comprises of the following folder structure:
|
||||
|
||||
```text
|
||||
.github/ - GitHub configuration files
|
||||
ISSUE_TEMPLATE/
|
||||
workflows/
|
||||
.husky/ - Git hooks
|
||||
.vscode/ - VS Code editor configuration
|
||||
components/ - Application components
|
||||
booking/
|
||||
dialog/
|
||||
team/
|
||||
ui/
|
||||
lib/ - Reusable code
|
||||
emails/
|
||||
events/
|
||||
forgot-password/messaging/
|
||||
integrations/CalDav/
|
||||
teams/
|
||||
pages/ - Most of the project lives here
|
||||
[user]/ - Booking pages
|
||||
api/ - The backend API
|
||||
auth/ - Next-Auth.js and other authentication routes
|
||||
availability/
|
||||
bookings/
|
||||
cancel/
|
||||
event-types/
|
||||
integrations/
|
||||
reschedule/
|
||||
settings/
|
||||
team/
|
||||
prisma/ - The database schema and migrations
|
||||
migrations/
|
||||
public/ - Images and static files
|
||||
integrations/
|
||||
styles/
|
||||
test/lib/
|
||||
```
|
||||
33
apps/docs/pages/developer/pull-requests.mdx
Normal file
@@ -0,0 +1,33 @@
|
||||
# Pull Requests
|
||||
|
||||
## Requirements
|
||||
|
||||
We have a number of requirements for PRs to ensure they are as easy to review as possible and to ensure that they are up to standard with the code.
|
||||
|
||||
### Title & Content
|
||||
|
||||
Start by providing a short and concise title. Don’t put something generic (e.g. bug fixes), and instead mention more specifically what your PR achieves, for instance “Fixes dropdown not expanding on settings page”.
|
||||
|
||||
For the PR description, you should go into much greater detail about what your PR adds or fixes. Firstly, the description should include a link to any relevant issues or discussions surrounding the feature or bug that your PR addresses.
|
||||
|
||||
#### Feature PRs
|
||||
|
||||
Give a functional overview of how your feature works, including how the user can use the feature. Then, share any technical details in an overview of how the PR works (e.g. “Once the user enters their password, the password is hashed using BCrypt and stored in the Users database field”).
|
||||
|
||||
#### Bug Fix PRs
|
||||
|
||||
Give an overview of how your PR fixes the bug both as a high-level overview and a technical explanation of what caused the issue and how your PR resolves this.
|
||||
|
||||
Feel free to add a short video or screenshots of what your PR achieves. Loom is a great way of sharing short videos.
|
||||
|
||||
### Code Quality & Styling
|
||||
|
||||
All submitted code must match our [code styling](/docs/code-styling) standards. We will reject pull requests that differ significantly from our standardised code styles.
|
||||
|
||||
All code is automatically checked by Codacy and our linting process, and will notify you if there are any issues with the code that you submit. We require that code passes these quality checks before merging.
|
||||
|
||||
## PR review process
|
||||
|
||||
At least two members of the Calendso team should review and approve any PR before it is merged.
|
||||
|
||||
Once two members of the team have approved this, someone from the team will merge the PR. If you are part of the Calendso team, you should merge your own PRs once you have received both approvals.
|
||||
39
apps/docs/pages/event-types.mdx
Normal file
@@ -0,0 +1,39 @@
|
||||
# Event Types
|
||||
Event types allow you to create different events for different occasions when booking a time with you in your calendar. These can be named differently, have different time durations and the choice of platform can change.
|
||||
|
||||
## Creating an event type
|
||||
1. Go to [Your Event Types](https://app.cal.com/event-types).
|
||||
2. Click the button at the top right of your screen saying '+ New Event Type'.
|
||||
3. Create the title of your new event.
|
||||
4. Confirm the auto-generated event type URL.
|
||||
5. Create a description on what your event will be used for.
|
||||
6. Decide on the amount of minutes you wish for this event to last for.
|
||||
7. Press 'Continue'
|
||||
8. Your event has now been created!
|
||||
|
||||
## Editing event types
|
||||
1. Go to [Your Event Types](https://app.cal.com/event-types).
|
||||
2. Click anywhere within the box of the event you would like to edit.
|
||||
(From here you can edit the basic settings of your event)
|
||||
3. To get the advanced options, at the bottom of your event setting click 'Show Advanced Settings'
|
||||
4. After you have finished editing the event type, scroll to the bottom of your page and select 'Update'
|
||||
5. Your event type has now been updated.
|
||||
|
||||
## Deleting event types
|
||||
1. Go to [Your Event Types](https://app.cal.com/event-types).
|
||||
2. Click anywhere within the box of the event, just like you would if you were editing the event.
|
||||
3. From this page, just to the right, a button saying 'delete' will appear. Click this and your event will be deleted!
|
||||
|
||||
## How to block a time slot before/after a meeting
|
||||
You can block out a time frame in your calendar only after the meeting. You can do this by selecting `Show advanced settings` of your Event Type. The setting is labeled `Time-slot intervals`.
|
||||
|
||||
## Setting up specific availability for each type of Event
|
||||
Head to `Show advanced settings` of your event. At the bottom you can set up specific availability for different Event Types.
|
||||
|
||||
## Availability not showing on a certain day in your calendar
|
||||
Head over to your event and once you click on `Show advanced settings`, make sure your time zones are correct. Also, check if you have any calendar events scheduled that could overlap with your availability.
|
||||
|
||||
## People can't book me even though there is still a couple of hours left on my availability for today
|
||||
Head over to your event and once you click on `Show advanced settings`, have a look at the `Minimum booking notice`. It probably overlaps with your availability so make sure that notice fits your desired time frame for meetings. For example, if someone wants to book a meeting with you at 16:15 and it’s already 15:30, your 90 minutes minimum booking notice doesn’t allow that meeting to be booked.
|
||||
|
||||
|
||||
13
apps/docs/pages/faq.mdx
Normal file
@@ -0,0 +1,13 @@
|
||||
# Frequently asked questions
|
||||
|
||||
## Does Cal.com support a custom domain?
|
||||
This is possible with our self-hosted option.
|
||||
|
||||
## Is there a possibility of multi-bookings for events where more people can book at the same time?
|
||||
As it stands this is currently not possible. We always keep an eye on the limitations like these that our users point to us. We’ve had requests in the past for the multi-booking feature and this is on our priority list.
|
||||
|
||||
## How to quickly block further bookings?
|
||||
1. Click on the lower left corner of your dashboard where your username is displayed.
|
||||
2. That initates a dropdown menu. Click on `Set youself as away`.
|
||||
|
||||
This is a method to disable your Cal.com account which won't allow any bookings once initiated. However, bookings made before turning on *away mode* will still be booked.
|
||||
30
apps/docs/pages/import.mdx
Normal file
@@ -0,0 +1,30 @@
|
||||
import Callout from 'nextra-theme-docs/callout';
|
||||
|
||||
# Import data from other scheduling tools
|
||||
|
||||
When setting up your Cal.com account via the onboarding process, you can import data from other scheduling tools, such as Calendly or SavvyCal. All that you need to import your data is an access token, which you can retrieve from your Calendly/SavvyCal account.
|
||||
|
||||
Once you've pasted your access token, we import your account data in less than a second.
|
||||
|
||||
Naturally, we take security very seriously when it comes to importing your data from other accounts, so that's why we never store your access token, and use it once to query the Calendly/SavvyCal APIs, populate your account with the data it returns, and then your key is destroyed from memory. All of the importer code can be [freely viewed on GitHub](https://github.com/calcom/cal.com/tree/main/pages/api/import), so you can be assured we're not using your data for malicious purposes.
|
||||
|
||||
## Calendly
|
||||
The following steps will help you retrieve your Calendly access token, which you will need to present at the import screen of the onboarding process.
|
||||
1. Go to the Calendly website and click on **My Account** in the top right
|
||||
2. Now click on **Integrations** in the top right
|
||||
3. Scroll to the bottom and click on **API & Webhooks**
|
||||
4. Click the blue **Generate new token** button and type in anything you'd like as the app name
|
||||
5. Press **Copy token** and then paste it into the Cal.com importer
|
||||
<Callout>
|
||||
Even though we don't store your access token, you can press **Revoke** to destroy the access token from the **API & Webhooks** page once the import is complete.
|
||||
</Callout>
|
||||
|
||||
## SavvyCal
|
||||
The following steps will help you retrieve your SavvyCal access token, which you will need to present at the import screen of the onboarding process.
|
||||
1. Head to the SavvyCal website and click **Settings** in the sidebar
|
||||
2. Click the **Developers** tab, and under **Personal access tokens**, click the blue **Create a token** link
|
||||
3. Give the token any name you'd like, and then confirm
|
||||
4. Click to copy the token, and then paste the token into the Cal.com importer
|
||||
<Callout>
|
||||
Even though we don't store your access token, you can press the trash icon to revoke the access token from the **Developers** tab once the import is complete.
|
||||
</Callout>
|
||||
13
apps/docs/pages/index.mdx
Normal file
@@ -0,0 +1,13 @@
|
||||
import Bleed from 'nextra-theme-docs/bleed'
|
||||
|
||||
# Cal.com Documentation
|
||||
|
||||
Welcome to our product documentation, where you can explore advice and explanations for all of our features, as well as discover new tips and tricks to get the most out of your subscription.
|
||||
|
||||
This is also the home of our design system documentation and developer docs.
|
||||
|
||||
If you don't already know what Cal.com is about, please head over to [our website](https://cal.com), where you can learn more about the product before venturing into the documentation.
|
||||
|
||||
Want to help make these docs even better? This site is fully open source, and the source code is available on [GitHub](https://github.com/calcom/docs). You can also click the edit button at the bottom of any page to start editing the source code and start a pull request.
|
||||
|
||||
<Bleed></Bleed>
|
||||
36
apps/docs/pages/integrations/google.mdx
Normal file
@@ -0,0 +1,36 @@
|
||||
# Google Calendar
|
||||
The Google Calendar integration checks for availability in your Google Calendars and creates bookings for you.
|
||||
|
||||
## Removing Permissions for Cal to access your Google Account
|
||||
|
||||
1. Go to your [Google Account](https://myaccount.google.com/).
|
||||
2. On the left, click Data & privacy.
|
||||
3. Scroll to "Data from apps and services you use."
|
||||
4. Under "Download or delete your data," click Delete a Google service. You may need to sign in again.
|
||||
5. Next to the product you want to remove, click Delete.
|
||||
6. Follow the steps on the screen.
|
||||
|
||||
To remove a product from your account that isn't listed in your Google Account, visit [Google Support](https://support.google.com) for more info on a specific product.
|
||||
|
||||
## Obtaining the Google API Credentials
|
||||
1. Open [Google API Console](https://console.cloud.google.com/apis/dashboard). If you don't have a project in your Google Cloud subscription, you'll need to create one before proceeding further. Under Dashboard pane, select Enable APIS and Services.
|
||||
2. In the search box, type calendar and select the Google Calendar API search result.
|
||||
3. Enable the selected API.
|
||||
4. Next, go to the [OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent) from the side pane. Select the app type (Internal or External) and enter the basic app details on the first page.
|
||||
5. In the second page on Scopes, select Add or Remove Scopes. Search for Calendar.event and select the scope with scope value `.../auth/calendar.events`, `.../auth/calendar.readonly`, `.../auth/calendar` and select Update.
|
||||
6. In the third page (Test Users), add the Google account(s) you'll using. Make sure the details are correct on the last page of the wizard and your consent screen will be configured.
|
||||
7. Now select [Credentials](https://console.cloud.google.com/apis/credentials) from the side pane and then select Create Credentials. Select the OAuth Client ID option.
|
||||
8. Select Web Application as the Application Type.
|
||||
9. Under Authorized redirect URI's, select Add URI and then add the URI `<CALENDSO URL>/api/integrations/googlecalendar/callback` replacing CALENDSO URL with the URI at which your application runs.
|
||||
10. The key will be created and you will be redirected back to the Credentials page. Select the newly generated client ID under OAuth 2.0 Client IDs.
|
||||
11. Select Download JSON. Copy the contents of this file and paste the entire JSON string in the .env file as the value for GOOGLE_API_CREDENTIALS key.
|
||||
|
||||
## Where to find the Google Meet integration?
|
||||
|
||||
Google Meet is a part of the Google Calendar integration and it should be available once you've added your Google Calendar. Just select Google Meet as location for your Event Type:
|
||||
|
||||
1. Go to your `Event Types`.
|
||||
2. Click on the `Location` drop-down menu.
|
||||
3. Select Google Meet as the location of your meeting.
|
||||
|
||||
Once your Event Type slot is booked, it will automatically generate the Google Meet link for the meeting.
|
||||
17
apps/docs/pages/integrations/introduction.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
# Integrations
|
||||
|
||||
## Connecting new calendars
|
||||
1. Go to the [Cal App Store](https://app.cal.com/integrations).
|
||||
2. Located at the top right of the screen, press the button saying '+ Connect A New App'
|
||||
3. Choose the account your calendar is connected too by clicking 'Add'. (e.g. Google, Office 365, Zoom)
|
||||
4. You will be redirected to the log in page of the chosen account.
|
||||
5. Allow Cal access to view and edit your calendars.
|
||||
6. You will be sent back to the [Cal App Store](https://app.cal.com/integrations). From here you will now be able to see your connected calendar!
|
||||
|
||||
## How to choose the primary Calendar?
|
||||
|
||||
If you have two or more integrated calendars and you want your events to show in only one, you can define a primary calendar like this:
|
||||
|
||||
1. Go to your [Integrations](https://app.cal.com/integrations) page.
|
||||
2. Next to your `Calendars` you will see a dropdown that says `Create events on:`.
|
||||
3. Select your primary calendar.
|
||||
9
apps/docs/pages/integrations/meta.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"introduction": "Introduction",
|
||||
"google": "Google",
|
||||
"microsoft": "Microsoft",
|
||||
"zoom": "Zoom",
|
||||
"stripe": "Stripe",
|
||||
"zapier": "Zapier"
|
||||
}
|
||||
|
||||
20
apps/docs/pages/integrations/microsoft.mdx
Normal file
@@ -0,0 +1,20 @@
|
||||
# Outlook/Microsoft 365
|
||||
The Outlook integration enables you to use your outlook.com or Microsoft 365 account to use for conflict checking and event bookings.
|
||||
|
||||
## Obtaining Microsoft Graph Client ID and Secret
|
||||
1. Open [Azure App Registration](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and select New registration
|
||||
2. Name your application
|
||||
3. Set **Who can use this application or access this API?** to **Accounts in any organizational directory (Any Azure AD directory - Multitenant)**
|
||||
4. Set the **Web** redirect URI to `<CALENDSO URL>/api/integrations/office365calendar/callback` replacing CALENDSO URL with the URI at which your application runs.
|
||||
5. Use **Application (client) ID** as the **MS_GRAPH_CLIENT_ID** attribute value in .env
|
||||
6. Click **Certificates & secrets** create a new client secret and use the value as the **MS_GRAPH_CLIENT_SECRET** attribute
|
||||
|
||||
## Removing Permissions for Cal to access your Microsoft Workplace Account
|
||||
|
||||
Hover over Cal.com in the my apps portal, then select `manage your application`.
|
||||
|
||||
The top part of permissions window shows what you personally consented to. Examples of apps permissions include the ability to access your calendar, contacts, or camera.
|
||||
|
||||
You can revoke any of the permissions you consented to by selecting `Revoke Permissions`, however removing a permission may break some of the apps functionality. If you have problems after you remove permissions or accounts, contact your organization's Helpdesk for additional assistance.
|
||||
|
||||
If you require more help, head over the Microsoft Documentation Page about [Managing Applications](https://docs.microsoft.com/en-us/azure/active-directory/user-help/my-applications-portal-permissions-saved-accounts)
|
||||
19
apps/docs/pages/integrations/stripe.mdx
Normal file
@@ -0,0 +1,19 @@
|
||||
# Stripe Payments
|
||||
|
||||
The Stripe integration allows users to add payments to their bookings.
|
||||
|
||||
## Adding the stripe integration
|
||||
|
||||
1. Go to the [Cal App Store](https://app.cal.com/integrations).
|
||||
2. Located near the top of this page will be the integration 'Stripe' and located to the right will be a button called 'Connect', press this.
|
||||
3. You will be redirected to Stripe requesting for Cal.com to be authorized access. Press 'Accept'.
|
||||
|
||||
This stripe integration has now successfully been added.
|
||||
|
||||
## Removing the stripe integration
|
||||
|
||||
1. Go to the [Cal App Store](https://app.cal.com/integrations).
|
||||
2. Located near the top of this page will be the integration 'Stripe' and located to the right will be a button called 'Disconnect', press this.
|
||||
3. A confirmation pop up box will appear, to confirm press the button saying 'Yes, disconnect integration'.
|
||||
|
||||
This stripe integration has now successfully been disconnected.
|
||||
3
apps/docs/pages/integrations/zapier.mdx
Normal file
@@ -0,0 +1,3 @@
|
||||
## Do you have a Zapier integration?
|
||||
|
||||
We are currently working on it, but it isn’t live just yet. Until then, you can use our Webhooks integration and use Zapier's “Webhooks by Zapier”.
|
||||
45
apps/docs/pages/integrations/zoom.mdx
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Zoom
|
||||
|
||||
The Zoom integration automatically creates Zoom meetings for your bookings.
|
||||
|
||||
## Connecting your Zoom account
|
||||
|
||||
1. Go to the App Store page, and click the 'Add new integration' button.
|
||||
2. Next to Zoom, go ahead and click the 'Add' button.
|
||||
3. You will now be taken to Zoom to sign into your account and authorize Cal.
|
||||
|
||||
## Disconnecting your Zoom account
|
||||
|
||||
1. Go to the App Store page, and click on your Zoom integration in the list.
|
||||
2. On the right hand side, click the Delete App button.
|
||||
|
||||
This will remove the integration from Cal. Cal will not perform any actions on your account once the integration is removed. However, if you want to revoke Cal's permissions from your Zoom account, perform the following steps:
|
||||
|
||||
1. Log into your Zoom account and navigate to the App Marketplace
|
||||
2. Click Manage > Installed Apps or search for the Cal app
|
||||
3. Click on the Cal app
|
||||
4. Click Uninstall
|
||||
|
||||
## How we interact with your Zoom account
|
||||
|
||||
We only need the ability to create meetings, so when somebody books an event with you, Cal can communicate with Zoom and create the corresponding meeting.
|
||||
|
||||
## Setting up Zoom on your self-hosted instance
|
||||
|
||||
1. Open [Zoom Marketplace](https://marketplace.zoom.us/) and sign in with your Zoom account.
|
||||
2. On the upper right, click "Develop" => "Build App".
|
||||
3. On "OAuth", select "Create".
|
||||
4. Name your App.
|
||||
5. Choose "User-managed app" as the app type.
|
||||
6. De-select the option to publish the app on the Zoom App Marketplace.
|
||||
7. Click "Create".
|
||||
8. Now copy the Client ID and Client Secret to your .env file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields.
|
||||
9. Set the Redirect URL for OAuth `<CALENDSO URL>/api/integrations/zoomvideo/callback` replacing CALENDSO URL with the URI at which your application runs.
|
||||
10. Also add the redirect URL given above as an allowlist URL and enable "Subdomain check". Make sure it says "saved" below the form.
|
||||
11. You don't need to provide basic information about your app. Instead click at "Scopes" and then at "+ Add Scopes". On the left, click the category "Meeting" and check the scope `meeting:write`.
|
||||
12. Click "Done".
|
||||
13. You're good to go. Now you can easily add your Zoom integration in the Cal settings.
|
||||
15
apps/docs/pages/meta.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"index": "Home",
|
||||
"self-hosting": "Self-hosting",
|
||||
"availability": "Availability",
|
||||
"bookings": "Bookings",
|
||||
"event-types": "Event Types",
|
||||
"teams": "Teams",
|
||||
"integrations": "Integrations",
|
||||
"webhooks": "Webhooks",
|
||||
"settings": "Settings",
|
||||
"import": "Import",
|
||||
"billing": "Billing",
|
||||
"developer": "Developer",
|
||||
"faq": "FAQs"
|
||||
}
|
||||
45
apps/docs/pages/self-hosting/docker.mdx
Normal file
@@ -0,0 +1,45 @@
|
||||
# Docker
|
||||
|
||||
The Docker configuration for Cal is an effort powered by people within the community. Cal does not provide official support for Docker, but we will accept fixes and documentation. Use at your own risk.
|
||||
|
||||
The Docker configuration can be found [in our docker repository](https://github.com/calcom/docker).
|
||||
|
||||
## Requirements
|
||||
|
||||
Make sure you have `docker` & `docker-compose` installed on the server / system.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Option #1: Docker Hub
|
||||
|
||||
```bash
|
||||
docker pull calendso/calendso
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
### Option #2: Cloning
|
||||
|
||||
1. Clone calendso-docker
|
||||
|
||||
```bash
|
||||
git clone git@github.com:calendso/calendso-docker.git --recursive
|
||||
```
|
||||
|
||||
2. Update `.env` if needed
|
||||
|
||||
3. Build and start calendso
|
||||
|
||||
```
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
4. Start prisma studio
|
||||
```
|
||||
docker-compose exec calendso -- npx prisma studio
|
||||
```
|
||||
5. Open a browser to [port 5555](http://localhost:5555) on your localhost to look at or modify the database content.
|
||||
|
||||
6. Click on the `User` model to add a new user record.
|
||||
7. Fill out the fields (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
|
||||
8. Open a browser to [port 3000](http://localhost:3000) on your localhost and login with your just created, first user.
|
||||
124
apps/docs/pages/self-hosting/install.mdx
Normal file
@@ -0,0 +1,124 @@
|
||||
# Installation
|
||||
|
||||
To get a local copy up and running, please follow these simple steps.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Here is what you need to be able to run Cal.
|
||||
|
||||
- Node.js
|
||||
- PostgreSQL
|
||||
- Yarn _(recommended)_
|
||||
|
||||
> If you want to enable any of the available integrations, you may want to obtain additional credentials for each one. More details on this can be found below under the integrations category.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Clone the repo
|
||||
|
||||
```sh
|
||||
git clone https://github.com/calcom/cal.com.git
|
||||
```
|
||||
|
||||
1. Go to the project folder
|
||||
|
||||
```sh
|
||||
cd cal.com
|
||||
```
|
||||
|
||||
1. Copy `.env.example` to `.env`
|
||||
|
||||
```sh
|
||||
cp apps/web/.env.example apps/web/.env
|
||||
cp packages/prisma/.env.example packages/prisma/.env
|
||||
```
|
||||
|
||||
1. Install packages with yarn
|
||||
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
|
||||
### Quick start with `yarn dx`
|
||||
|
||||
> - **Requires Docker and Docker Compose to be installed**
|
||||
> - Will start a local Postgres instance with a few test users - the credentials will be logged in the console
|
||||
|
||||
```sh
|
||||
yarn dx
|
||||
```
|
||||
|
||||
### Manual setup
|
||||
|
||||
1. Configure database in the `packages/prisma/.env` file. Replace `<user>`, `<pass>`, `<db-host>`, `<db-port>` with their applicable values
|
||||
|
||||
```text
|
||||
DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>'
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
<summary>
|
||||
If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick DB
|
||||
using Heroku
|
||||
</summary>
|
||||
|
||||
1. Create a free account with [Heroku](https://www.heroku.com/).
|
||||
|
||||
2. Create a new app.
|
||||
|
||||
<img
|
||||
width="306"
|
||||
alt="Create an App"
|
||||
src="https://user-images.githubusercontent.com/16905768/115322780-b3d58c00-a17e-11eb-8a52-b758fb0ea942.png"
|
||||
/>
|
||||
|
||||
3. In your new app, go to `Overview` and next to `Installed add-ons`, click `Configure Add-ons`. We need this to set up our database.
|
||||

|
||||
|
||||
4. Once you clicked on `Configure Add-ons`, click on `Find more add-ons` and search for `postgres`. One of the options will be `Heroku Postgres` - click on that option.
|
||||

|
||||
|
||||
5. Once the pop-up appears, click `Submit Order Form` - plan name should be `Hobby Dev - Free`.
|
||||
|
||||
<img
|
||||
width="512"
|
||||
alt="Submit Order Form"
|
||||
src="https://user-images.githubusercontent.com/16905768/115323265-b4baed80-a17f-11eb-99f0-d67f019aa6df.png"
|
||||
/>
|
||||
|
||||
6. Once you completed the above steps, click on your newly created `Heroku Postgres` and go to its `Settings`.
|
||||

|
||||
|
||||
7. In `Settings`, copy your URI to your Cal.com .env file and replace the `postgresql://<user>:<pass>@<db-host>:<db-port>` with it.
|
||||

|
||||

|
||||
|
||||
8. To view your DB, once you add new data in Prisma, you can use [Heroku Data Explorer](https://heroku-data-explorer.herokuapp.com/).
|
||||
</details>
|
||||
|
||||
1. Set a 32 character random string in your `apps/web/.env` file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one).
|
||||
1. Set up the database using the Prisma schema (found in `packages/prisma/schema.prisma`)
|
||||
|
||||
```sh
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
1. Run (in development mode)
|
||||
|
||||
```sh
|
||||
yarn dev --scope=@calcom/web
|
||||
```
|
||||
|
||||
### Setting up your first user
|
||||
|
||||
1. Open [Prisma Studio](https://www.prisma.io/studio) to look at or modify the database content:
|
||||
|
||||
```sh
|
||||
npx prisma studio
|
||||
```
|
||||
|
||||
1. Click on the `User` model to add a new user record.
|
||||
1. Fill out the fields `email`, `username`, `password`, and set `metadata` to empty `{}` (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
|
||||
> New users are set on a `TRIAL` plan by default. You might want to adjust this behavior to your needs in the `prisma/schema.prisma` file.
|
||||
1. Open a browser to [port 3000](http://localhost:3000) and login with your just created, first user.
|
||||
6
apps/docs/pages/self-hosting/meta.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"install": "Installation",
|
||||
"upgrade": "Upgrade",
|
||||
"docker": "Docker",
|
||||
"vercel": "Vercel"
|
||||
}
|
||||
43
apps/docs/pages/self-hosting/upgrade.mdx
Normal file
@@ -0,0 +1,43 @@
|
||||
# Upgrading
|
||||
|
||||
**Warning**: When performing database migrations, you may lose data if the migration is not done properly.
|
||||
|
||||
1. Pull the current version:
|
||||
```
|
||||
git pull
|
||||
```
|
||||
2. Apply database migrations by running <b>one of</b> the following commands:
|
||||
|
||||
In a development environment, run:
|
||||
|
||||
```
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
(this can clear your development database in some cases)
|
||||
|
||||
In a production environment, run:
|
||||
|
||||
```
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
3. Check the `.env.example` and compare it to your current `.env` file. In case there are any fields not present
|
||||
in your current `.env`, add them there.
|
||||
|
||||
For the current version, especially check if the variable `BASE_URL` is present and properly set in your environment, for example:
|
||||
|
||||
```
|
||||
BASE_URL='https://yourdomain.com'
|
||||
```
|
||||
|
||||
4. Start the server. In a development environment, just do:
|
||||
```
|
||||
yarn dev
|
||||
```
|
||||
For a production build, run for example:
|
||||
```
|
||||
yarn build
|
||||
yarn start
|
||||
```
|
||||
5. Enjoy the new version.
|
||||
46
apps/docs/pages/self-hosting/vercel.mdx
Normal file
@@ -0,0 +1,46 @@
|
||||
# Vercel
|
||||
|
||||
## Requirements
|
||||
|
||||
You need a PostgresDB database hosted somewhere. [Heroku](https://www.heroku.com) and [Supabase](https://supabase.com/) offer great free options.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Local settings
|
||||
|
||||
1. Fork and clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-fork>/cal.com.git
|
||||
```
|
||||
|
||||
2. Copy the `.env.example` file in `apps/web`, rename it to `.env` and fill it with your settings ([See manual setup](https://github.com/calcom/cal.com#manual) and [Obtaining the Google API Credentials](https://github.com/calcom/cal.com#obtaining-the-google-api-credentials))
|
||||
|
||||
3. Install packages with `yarn`
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
4. Set up the database using the Prisma schema (found in `prisma/schema.prisma`)
|
||||
|
||||
```sh
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
5. Open [Prisma Studio](https://www.prisma.io/studio) to look at or modify the database content:
|
||||
```
|
||||
npx prisma studio
|
||||
```
|
||||
6. Click on the `User` model to add a new user record.
|
||||
7. Fill out the fields (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
|
||||
8. Open a browser to [port 3000](http://localhost:3000) on your localhost and login with your just created, first user.
|
||||
|
||||
### Deployment
|
||||
|
||||
1. Create a new project on Vercel
|
||||
1. Import from your forked repository
|
||||
1. Set the Environment Variables
|
||||
1. Set the root directory to `apps/web`
|
||||
1. Override the build command to `cd ../.. && npx turbo run build --scope=@calcom/web --include-dependencies --no-deps`
|
||||
1. Hit Deploy
|
||||
52
apps/docs/pages/settings.mdx
Normal file
@@ -0,0 +1,52 @@
|
||||
# Settings
|
||||
## Setting up or making changes to your Profile
|
||||
|
||||
1. Go to your [Profile Settings](https://app.cal.com/settings/profile).
|
||||
2. From this page you are able to edit the following:
|
||||
- Your URL Username
|
||||
- Your Display Name
|
||||
- Your About Information
|
||||
- Change your Profile Picture
|
||||
- Your Local Time Zone
|
||||
- Your Chosen 'First Day Of The Week'
|
||||
- Light or Dark Mode for your Booking Page
|
||||
- Enabling or Disabling cal.com Branding on your Booking Page
|
||||
3. Once you have completed all your changes, press that 'save' button located at the bottom right of your page.
|
||||
|
||||
## Reset your password
|
||||
|
||||
1. Go to [your account security settings](https://app.cal.com/settings/security).
|
||||
2. Located at the top of your screen, you will see two boxes.
|
||||
3. Enter your Old Password and New Password.
|
||||
4. Click the button 'Save' located to the bottom right of your new password.
|
||||
5. You have now successfully changed your password!
|
||||
|
||||
## Change your email
|
||||
|
||||
Go to [Profile Settings](https://app.cal.com/settings/profile). There, you will see the email associated with your account which you can then update. You’d just need to log out and back in to see the change take effect.
|
||||
|
||||
## Enable 2FA
|
||||
|
||||
1. Go to [Your Account Security Settings](https://app.cal.com/settings/security).
|
||||
2. Located at the bottom of your screen, click on the tab labeled 'Enable Two-Factor Authentication'.
|
||||
3. Enter your Password.
|
||||
4. In your authenticator app, scan the QR Code presented on your screen.
|
||||
5. Once Scanned, press 'Next' and then enter the code presented within your Authentication App
|
||||
6. Press 'Enabled'
|
||||
|
||||
You have now successfully enabled Two-Factor Authentication
|
||||
|
||||
## Disable 2FA
|
||||
1. Go to [Your Account Security Settings](https://app.cal.com/settings/security).
|
||||
2. Located at the bottom of your screen, click on the tab labeled 'Disable Two-Factor Authentication'.
|
||||
3. Enter your Password.
|
||||
|
||||
You have now successfully disabled Two-Factor Authentication
|
||||
|
||||
## How to delete my account
|
||||
|
||||
You can delete your account from within the [Settings](https://app.cal.com/settings/profile) option. Just scroll all the way down and click on `Delete Account`.
|
||||
|
||||
## How to change the language
|
||||
|
||||
Go to your [Profile Settings](https://app.cal.com/settings/profile). Under `Language` you will see the dropdown menu and you can use it to select your desired language.
|
||||
15
apps/docs/pages/style.css
Normal file
@@ -0,0 +1,15 @@
|
||||
@font-face {
|
||||
font-family: 'Cal Sans';
|
||||
src: url("https://cal.com/cal.ttf");
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Cal Sans';
|
||||
font-weight: normal;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
53
apps/docs/pages/teams.mdx
Normal file
@@ -0,0 +1,53 @@
|
||||
# Teams
|
||||
|
||||
## How do I create a new team?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams).
|
||||
2. Press the button displayed on your screen called '+ New Team'
|
||||
3. Enter the name you wish to call your team.
|
||||
4. After entering the name press the 'Create Team' button located just under your new team name.
|
||||
5. You have now created your new team.
|
||||
|
||||
Creating a team will allow you to create new event types for the team, invite team members and much more!
|
||||
|
||||
## How do I change my teams URL?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams) and select the team you wish to edit.
|
||||
2. Located at the top of your teams settings will be a team-url bar, from here you can input your requested teams url.
|
||||
3. Once complete make sure you press 'save' at the bottom of the page.
|
||||
|
||||
## How do I change my teams name?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams) and select the team you wish to edit.
|
||||
2. Located in the 2nd row of your teams settings will be a Team Name bar, from here you can input your requested team name.
|
||||
3. Once complete make sure you press 'save' at the bottom of the page.
|
||||
|
||||
## How do I add and remove a description of my team?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams) and select the team you wish to edit.
|
||||
2. Located below your team name entry box is a large text box labeled 'About',
|
||||
|
||||
## How do I upload my team logo?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams) and select the team you wish to edit.
|
||||
2. Located under your teams subscription will be a box that says 'Upload a logo', press this box.
|
||||
3. Press 'choose a file' and locate a file from your machine you wish to use as your team logo.
|
||||
4. Once complete make sure you press 'save' at the bottom of the page.
|
||||
|
||||
## How do I manage team members?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams) and select the team you wish to edit.
|
||||
2. Located at the bottom of your page is your team members, from here you can choose to add or remove team members and even change their role which could be Member, Admin or Owner.
|
||||
|
||||
## How do I delete my team I created?
|
||||
|
||||
1. Go to [Your Teams Settings](https://app.cal.com/settings/teams).
|
||||
2. From here you will be able to see a list of teams you have created or apart of, located to the right of the team you wish to delete you can find three dots (...)
|
||||
3. Press the 3 dots (...) then 'Disband Team'
|
||||
4. This will brin gup a prompt confirming if you wish to disband your team, if your are sure you can press the button labeled 'Yes, disband team'
|
||||
|
||||
Your team has now successfully been deleted.
|
||||
|
||||
## Where can I find my team's Event Types?
|
||||
|
||||
Once you open `Event Types` on your dashboard, you will find your team's Event Types below your individual ones.
|
||||
40
apps/docs/pages/webhooks.mdx
Normal file
@@ -0,0 +1,40 @@
|
||||
# Webhooks
|
||||
## Create a new Webhook
|
||||
|
||||
1. Go to [Your Integrations](https://app.cal.com/integrations).
|
||||
2. Scrolling down to the bottom of the page you will see a button called ‘New Webhook’. Press this button to open up the box which will ask for details on creating the new webhooks.
|
||||
3. Select whatever event this triggers, this may be Create, Cancelled or Reschedule.
|
||||
4. Once this is completed, insert the Subscriber URL then click 'Save' located at the bottom right of the box.
|
||||
|
||||
## Edit an existing Webhook
|
||||
|
||||
1. Go to [Your Integrations](https://app.cal.com/integrations).
|
||||
2. Scrolling down to the bottom of the page you will see an icon to the right of your webhook, this will be labeled edit webhook.
|
||||
3. Press the button and from here you can change any of the webhook settings. This could be changing the event that is triggered and this may be Create, Cancelled or Reschedule. Or you can change the Subscriber URL.
|
||||
|
||||
## Delete an existing Webhook
|
||||
|
||||
1. Go to [Your Integrations](https://app.cal.com/integrations).
|
||||
2. Scrolling down to the bottom of the page you will see an icon to the right of your webhook, this will be labeled delete webhook.
|
||||
3. Press the button and from here your webhook will no longer work and be deleted.
|
||||
|
||||
## Webhook metadata
|
||||
Metadata is a way to pass extra information to Cal.com about a booking that is returned through a webhook.
|
||||
|
||||
### Example
|
||||
The best way to explain this is with an example. Let's say you're a bank, and people register an account on your website, but you want them to book an onboarding call with your team to get set up. You could send them to your Cal.com booking link as part of your onboarding process, but when the webhook is returned, it may be difficult to match up which user booked a meeting with the user's account in your own database. Hence, you can pass a `user_id` value for instance as a URL parameter, which makes no difference to the booking process, but when the webhook is returned, you will receive the metadata as part of the webhook payload.
|
||||
|
||||
Metadata is passed as a URL parameter on top of your booking link and follows the following syntax:
|
||||
```text
|
||||
metadata[key_name]=value
|
||||
```
|
||||
|
||||
For example, if your booking link is `cal.com/rick/quick-chat`, you can pass a user ID of 123 like so:
|
||||
```text
|
||||
cal.com/rick/quick-chat?metadata[user_id]=123
|
||||
```
|
||||
|
||||
As a result, the webhook will be returned in this format:
|
||||
```text
|
||||
{ <other event details>, metadata: { user_id: 123 } }
|
||||
```
|
||||
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
9
apps/docs/public/browserconfig.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#292929</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
apps/docs/public/demo.png
Normal file
|
After Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 581 B After Width: | Height: | Size: 581 B |
|
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
19
apps/docs/public/site.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Cal.com",
|
||||
"short_name": "Cal.com",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#292929",
|
||||
"background_color": "#292929",
|
||||
"display": "standalone"
|
||||
}
|
||||
63
apps/docs/theme.config.js
Normal file
@@ -0,0 +1,63 @@
|
||||
export default {
|
||||
github: 'https://github.com/calcom/docs',
|
||||
docsRepositoryBase: 'https://github.com/calcom/docs/blob/master',
|
||||
titleSuffix: ' | Cal.com',
|
||||
logo: (
|
||||
<h4 className="m-0">
|
||||
Cal.com
|
||||
</h4>
|
||||
),
|
||||
head: (
|
||||
<>
|
||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta httpEquiv="Content-Language" content="en" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Explore advice and explanations for all of our features, and discover new tips and tricks to get the most out of your subscription."
|
||||
/>
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Explore advice and explanations for all of our features, and discover new tips and tricks to get the most out of your subscription."
|
||||
/>
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:image" content="https://cal.com/og-image.png" />
|
||||
<meta name="twitter:site:domain" content="docs.cal.com" />
|
||||
<meta name="twitter:url" content="https://docs.cal.com" />
|
||||
<meta name="og:title" content="Cal.com Documentation" />
|
||||
<meta name="og:image" content="https://cal.com/og-image.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="Cal.com Docs" />
|
||||
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
||||
<meta name="msapplication-TileColor" content="#ff0000" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
</>
|
||||
),
|
||||
search: true,
|
||||
prevLinks: true,
|
||||
nextLinks: true,
|
||||
footer: true,
|
||||
footerEditLink: 'Edit this page on GitHub',
|
||||
footerText: (
|
||||
<>© {new Date().getFullYear()} Cal.com, Inc. All rights reserved.</>
|
||||
),
|
||||
}
|
||||
3623
apps/docs/yarn.lock
Normal file
101
apps/web/.env.example
Normal file
@@ -0,0 +1,101 @@
|
||||
# Set this value to 'agree' to accept our license:
|
||||
# LICENSE: https://github.com/calendso/calendso/blob/main/LICENSE
|
||||
#
|
||||
# Summary of terms:
|
||||
# - The codebase has to stay open source, whether it was modified or not
|
||||
# - You can not repackage or sell the codebase
|
||||
# - Acquire a commercial license to remove these terms by visiting: cal.com/sales
|
||||
NEXT_PUBLIC_LICENSE_CONSENT=''
|
||||
|
||||
# ⚠️ ⚠️ ⚠️ DATABASE_URL got moved to `packages/prisma/.env.example` ⚠️ ⚠️ ⚠️
|
||||
|
||||
# Needed to enable Google Calendar integration and Login with Google
|
||||
# @see https://github.com/calendso/calendso#obtaining-the-google-api-credentials
|
||||
GOOGLE_API_CREDENTIALS='{}'
|
||||
|
||||
# To enable Login with Google you need to:
|
||||
# 1. Set `GOOGLE_API_CREDENTIALS` above
|
||||
# 2. Set `GOOGLE_LOGIN_ENABLED` to `true`
|
||||
# When self-hosting please ensure you configure the Google integration as an Internal app so no one else can login to your instance
|
||||
# @see https://support.google.com/cloud/answer/6158849#public-and-internal&zippy=%2Cpublic-and-internal-applications
|
||||
GOOGLE_LOGIN_ENABLED=false
|
||||
|
||||
BASE_URL='http://localhost:3000'
|
||||
NEXT_PUBLIC_APP_URL='http://localhost:3000'
|
||||
|
||||
JWT_SECRET='secret'
|
||||
# This is used so we can bypass emails in auth flows for E2E testing
|
||||
PLAYWRIGHT_SECRET=
|
||||
|
||||
# To enable SAML login, set both these variables
|
||||
# @see https://github.com/calendso/calendso/tree/main/ee#setting-up-saml-login
|
||||
# SAML_DATABASE_URL="postgresql://postgres:@localhost:5450/cal-saml"
|
||||
# SAML_ADMINS='pro@example.com'
|
||||
# If you use Heroku to deploy Postgres (or use self-signed certs for Postgres) then uncomment the follow line.
|
||||
# @see https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
|
||||
##PGSSLMODE='no-verify'
|
||||
|
||||
# @see: https://github.com/calendso/calendso/issues/263
|
||||
# Required for Vercel hosting - set NEXTAUTH_URL to equal your BASE_URL
|
||||
# NEXTAUTH_URL='http://localhost:3000'
|
||||
|
||||
# Remove this var if you don't want Cal to collect anonymous usage
|
||||
NEXT_PUBLIC_TELEMETRY_KEY=js.2pvs2bbpqq1zxna97wcml.oi2jzirnbj1ev4tc57c5r
|
||||
|
||||
# Used for the Office 365 / Outlook.com Calendar integration
|
||||
MS_GRAPH_CLIENT_ID=
|
||||
MS_GRAPH_CLIENT_SECRET=
|
||||
|
||||
# Used for the Zoom integration
|
||||
ZOOM_CLIENT_ID=
|
||||
ZOOM_CLIENT_SECRET=
|
||||
|
||||
#Used for the Daily integration
|
||||
DAILY_API_KEY=
|
||||
DAILY_SCALE_PLAN=''
|
||||
|
||||
# Used for the Tandem integration -- contact support@tandem.chat to for API access.
|
||||
TANDEM_CLIENT_ID=""
|
||||
TANDEM_CLIENT_SECRET=""
|
||||
TANDEM_BASE_URL="https://tandem.chat"
|
||||
|
||||
# E-mail settings
|
||||
|
||||
# Cal uses nodemailer (@see https://nodemailer.com/about/) to provide email sending. As such we are trying to
|
||||
# allow access to the nodemailer transports from the .env file. E-mail templates are accessible within lib/emails/
|
||||
|
||||
# Configures the global From: header whilst sending emails.
|
||||
EMAIL_FROM='notifications@yourselfhostedcal.com'
|
||||
|
||||
# Configure SMTP settings (@see https://nodemailer.com/smtp/).
|
||||
# Note: The below configuration for Office 365 has been verified to work.
|
||||
EMAIL_SERVER_HOST='smtp.office365.com'
|
||||
EMAIL_SERVER_PORT=587
|
||||
EMAIL_SERVER_USER='<office365_emailAddress>'
|
||||
# Keep in mind that if you have 2FA enabled, you will need to provision an App Password.
|
||||
EMAIL_SERVER_PASSWORD='<office365_password>'
|
||||
# The following configuration for Gmail has been verified to work.
|
||||
# EMAIL_SERVER_HOST='smtp.gmail.com'
|
||||
# EMAIL_SERVER_PORT=465
|
||||
# EMAIL_SERVER_USER='<gmail_emailAddress>'
|
||||
## You will need to provision an App Password.
|
||||
## @see https://support.google.com/accounts/answer/185833
|
||||
# EMAIL_SERVER_PASSWORD='<gmail_app_password>'
|
||||
|
||||
# ApiKey for cronjobs
|
||||
CRON_API_KEY='0cc0e6c35519bba620c9360cfe3e68d0'
|
||||
|
||||
# Stripe Config
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY= # pk_test_...
|
||||
STRIPE_PRIVATE_KEY= # sk_test_...
|
||||
STRIPE_CLIENT_ID= # ca_...
|
||||
STRIPE_WEBHOOK_SECRET= # whsec_...
|
||||
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
|
||||
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
|
||||
|
||||
# Application Key for symmetric encryption and decryption
|
||||
# must be 32 bytes for AES256 encryption algorithm
|
||||
CALENDSO_ENCRYPTION_KEY=
|
||||
|
||||
# Intercom Config
|
||||
NEXT_PUBLIC_INTERCOM_APP_ID=
|
||||
2
apps/web/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
prisma/zod
|
||||
1
apps/web/.eslintrc.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("@calcom/config/eslint-preset");
|
||||
63
apps/web/.gitignore
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# .env file
|
||||
.env
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
/.yarn
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
.nyc_output
|
||||
playwright/videos
|
||||
playwright/screenshots
|
||||
playwright/artifacts
|
||||
playwright/results
|
||||
playwright/reports/*
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# Webstorm
|
||||
.idea
|
||||
|
||||
### VisualStudioCode template
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Typescript
|
||||
tsconfig.tsbuildinfo
|
||||
1
apps/web/.nvmrc
Normal file
@@ -0,0 +1 @@
|
||||
14.17
|
||||
1
apps/web/@prisma/client.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "@calcom/prisma/client";
|
||||
15
apps/web/@types/@wojtekmaj__react-daterange-picker.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
declare module "@wojtekmaj/react-daterange-picker/dist/entry.nostyle" {
|
||||
import { CalendarProps } from "react-calendar";
|
||||
export type DateRangePickerCalendarProps = Omit<
|
||||
CalendarProps,
|
||||
"calendarClassName" | "onChange" | "value"
|
||||
> & {
|
||||
calendarClassName?: string;
|
||||
onChange: (value: [Date, Date]) => void;
|
||||
value: [Date, Date];
|
||||
clearIcon: JSX.Element | null;
|
||||
calendarIcon: JSX.Element | null;
|
||||
rangeDivider: JSX.Element | null;
|
||||
};
|
||||
export default function DateRangePicker(props: DateRangePickerCalendarProps): JSX.Element;
|
||||
}
|
||||
257
apps/web/@types/ical.d.ts
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
// SPDX-FileCopyrightText: © 2019 EteSync Authors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// https://github.com/mozilla-comm/ical.js/issues/367#issuecomment-568493517
|
||||
declare module "ical.js" {
|
||||
function parse(input: string): any[];
|
||||
|
||||
export class helpers {
|
||||
public updateTimezones(vcal: Component): Component;
|
||||
}
|
||||
|
||||
class Component {
|
||||
public fromString(str: string): Component;
|
||||
|
||||
public name: string;
|
||||
|
||||
constructor(jCal: any[] | string, parent?: Component);
|
||||
|
||||
public toJSON(): any[];
|
||||
|
||||
public getFirstSubcomponent(name?: string): Component | null;
|
||||
public getAllSubcomponents(name?: string): Component[];
|
||||
|
||||
public getFirstPropertyValue<T = any>(name?: string): T;
|
||||
|
||||
public getFirstProperty(name?: string): Property;
|
||||
public getAllProperties(name?: string): Property[];
|
||||
|
||||
public addProperty(property: Property): Property;
|
||||
public addPropertyWithValue(name: string, value: string | number | Record<string, unknown>): Property;
|
||||
|
||||
public hasProperty(name?: string): boolean;
|
||||
|
||||
public updatePropertyWithValue(name: string, value: string | number | Record<string, unknown>): Property;
|
||||
|
||||
public removeAllProperties(name?: string): boolean;
|
||||
|
||||
public addSubcomponent(component: Component): Component;
|
||||
}
|
||||
|
||||
export class Event {
|
||||
public uid: string;
|
||||
public summary: string;
|
||||
public startDate: Time;
|
||||
public endDate: Time;
|
||||
public description: string;
|
||||
public location: string;
|
||||
public attendees: Property[];
|
||||
/**
|
||||
* The sequence value for this event. Used for scheduling.
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof Event
|
||||
*/
|
||||
public sequence: number;
|
||||
/**
|
||||
* The duration. This can be the result directly from the property, or the
|
||||
* duration calculated from start date and end date. Setting the property
|
||||
* will remove any `dtend` properties.
|
||||
*
|
||||
* @type {Duration}
|
||||
* @memberof Event
|
||||
*/
|
||||
public duration: Duration;
|
||||
/**
|
||||
* The organizer value as an uri. In most cases this is a mailto: uri,
|
||||
* but it can also be something else, like urn:uuid:...
|
||||
*/
|
||||
public organizer: string;
|
||||
/** The sequence value for this event. Used for scheduling */
|
||||
public sequence: number;
|
||||
/** The recurrence id for this event */
|
||||
public recurrenceId: Time;
|
||||
|
||||
public component: Component;
|
||||
|
||||
public constructor(
|
||||
component?: Component | null,
|
||||
options?: { strictExceptions: boolean; exepctions: Array<Component | Event> }
|
||||
);
|
||||
|
||||
public isRecurring(): boolean;
|
||||
public iterator(startTime?: Time): RecurExpansion;
|
||||
}
|
||||
|
||||
export class Property {
|
||||
public name: string;
|
||||
public type: string;
|
||||
|
||||
constructor(jCal: any[] | string, parent?: Component);
|
||||
|
||||
public getFirstValue<T = any>(): T;
|
||||
public getValues<T = any>(): T[];
|
||||
|
||||
public setParameter(name: string, value: string | string[]): void;
|
||||
public setValue(value: string | Record<string, unknown>): void;
|
||||
public setValues(values: (string | Record<string, unknown>)[]): void;
|
||||
public toJSON(): any;
|
||||
}
|
||||
|
||||
interface TimeJsonData {
|
||||
year?: number;
|
||||
month?: number;
|
||||
day?: number;
|
||||
hour?: number;
|
||||
minute?: number;
|
||||
second?: number;
|
||||
isDate?: boolean;
|
||||
}
|
||||
|
||||
export class Time {
|
||||
public fromString(str: string): Time;
|
||||
public fromJSDate(aDate: Date | null, useUTC: boolean): Time;
|
||||
public fromData(aData: TimeJsonData): Time;
|
||||
|
||||
public now(): Time;
|
||||
|
||||
public isDate: boolean;
|
||||
public timezone: string;
|
||||
public zone: Timezone;
|
||||
|
||||
public year: number;
|
||||
public month: number;
|
||||
public day: number;
|
||||
public hour: number;
|
||||
public minute: number;
|
||||
public second: number;
|
||||
|
||||
constructor(data?: TimeJsonData);
|
||||
public compare(aOther: Time): number;
|
||||
|
||||
public clone(): Time;
|
||||
public convertToZone(zone: Timezone): Time;
|
||||
|
||||
public adjust(
|
||||
aExtraDays: number,
|
||||
aExtraHours: number,
|
||||
aExtraMinutes: number,
|
||||
aExtraSeconds: number,
|
||||
aTimeopt?: Time
|
||||
): void;
|
||||
|
||||
public addDuration(aDuration: Duration): void;
|
||||
public subtractDateTz(aDate: Time): Duration;
|
||||
|
||||
public toUnixTime(): number;
|
||||
public toJSDate(): Date;
|
||||
public toJSON(): TimeJsonData;
|
||||
public get icaltype(): "date" | "date-time";
|
||||
}
|
||||
|
||||
export class Duration {
|
||||
public weeks: number;
|
||||
public days: number;
|
||||
public hours: number;
|
||||
public minutes: number;
|
||||
public seconds: number;
|
||||
public isNegative: boolean;
|
||||
public icalclass: string;
|
||||
public icaltype: string;
|
||||
}
|
||||
|
||||
export class RecurExpansion {
|
||||
public complete: boolean;
|
||||
public dtstart: Time;
|
||||
public last: Time;
|
||||
public next(): Time;
|
||||
public fromData(options);
|
||||
public toJSON();
|
||||
constructor(options: {
|
||||
/** Start time of the event */
|
||||
dtstart: Time;
|
||||
/** Component for expansion, required if not resuming. */
|
||||
component?: Component;
|
||||
});
|
||||
}
|
||||
|
||||
export class Timezone {
|
||||
public utcTimezone: Timezone;
|
||||
public localTimezone: Timezone;
|
||||
public convert_time(tt: Time, fromZone: Timezone, toZone: Timezone): Time;
|
||||
|
||||
public tzid: string;
|
||||
public component: Component;
|
||||
|
||||
constructor(
|
||||
data:
|
||||
| Component
|
||||
| {
|
||||
component: string | Component;
|
||||
tzid?: string;
|
||||
location?: string;
|
||||
tznames?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export class TimezoneService {
|
||||
public get(tzid: string): Timezone | null;
|
||||
public has(tzid: string): boolean;
|
||||
public register(tzid: string, zone: Timezone | Component);
|
||||
public remove(tzid: string): Timezone | null;
|
||||
}
|
||||
|
||||
export type FrequencyValues =
|
||||
| "YEARLY"
|
||||
| "MONTHLY"
|
||||
| "WEEKLY"
|
||||
| "DAILY"
|
||||
| "HOURLY"
|
||||
| "MINUTELY"
|
||||
| "SECONDLY";
|
||||
|
||||
export enum WeekDay {
|
||||
SU = 1,
|
||||
MO,
|
||||
TU,
|
||||
WE,
|
||||
TH,
|
||||
FR,
|
||||
SA,
|
||||
}
|
||||
|
||||
export class RecurData {
|
||||
public freq?: FrequencyValues;
|
||||
public interval?: number;
|
||||
public wkst?: WeekDay;
|
||||
public until?: Time;
|
||||
public count?: number;
|
||||
public bysecond?: number[] | number;
|
||||
public byminute?: number[] | number;
|
||||
public byhour?: number[] | number;
|
||||
public byday?: string[] | string;
|
||||
public bymonthday?: number[] | number;
|
||||
public byyearday?: number[] | number;
|
||||
public byweekno?: number[] | number;
|
||||
public bymonth?: number[] | number;
|
||||
public bysetpos?: number[] | number;
|
||||
}
|
||||
|
||||
export class RecurIterator {
|
||||
public next(): Time;
|
||||
}
|
||||
|
||||
export class Recur {
|
||||
constructor(data?: RecurData);
|
||||
public until: Time | null;
|
||||
public freq: FrequencyValues;
|
||||
public count: number | null;
|
||||
|
||||
public clone(): Recur;
|
||||
public toJSON(): Omit<RecurData, "until"> & { until?: string };
|
||||
public iterator(startTime?: Time): RecurIterator;
|
||||
public isByCount(): boolean;
|
||||
}
|
||||
}
|
||||
@@ -590,6 +590,12 @@ paths:
|
||||
title: Zoom
|
||||
imageSrc: integrations/zoom.svg
|
||||
description: Video Conferencing
|
||||
- installed: true
|
||||
type: tandem_video
|
||||
credential: null
|
||||
title: Tandem
|
||||
imageSrc: integrations/tandem.svg
|
||||
description: Virtual Office | Video Conferencing
|
||||
- installed: true
|
||||
type: caldav_calendar
|
||||
credential: null
|
||||
@@ -753,6 +759,18 @@ paths:
|
||||
summary: Gets and stores the OAuth token
|
||||
tags:
|
||||
- Integrations
|
||||
/api/integrations/tandemvideo/add:
|
||||
get:
|
||||
description: Gets the OAuth URL for a Tandem integration.
|
||||
summary: Gets the OAuth URL
|
||||
tags:
|
||||
- Integrations
|
||||
/api/integrations/tandemvideo/callback:
|
||||
post:
|
||||
description: Gets and stores the OAuth token for a Tandem integration.
|
||||
summary: Gets and stores the OAuth token
|
||||
tags:
|
||||
- Integrations
|
||||
/api/user/profile:
|
||||
patch:
|
||||
description: Updates a user's profile.
|
||||
@@ -13,14 +13,14 @@ export default function AddToHomescreen() {
|
||||
}
|
||||
}
|
||||
return !closeBanner ? (
|
||||
<div className="fixed sm:hidden bottom-0 inset-x-0 pb-2 sm:pb-5">
|
||||
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
|
||||
<div className="p-2 rounded-lg shadow-lg sm:p-3" style={{ background: "#2F333D" }}>
|
||||
<div className="flex items-center justify-between flex-wrap">
|
||||
<div className="w-0 flex-1 flex items-center">
|
||||
<span className="flex p-2 rounded-lg bg-opacity-30 bg-brand">
|
||||
<div className="fixed inset-x-0 bottom-0 pb-2 sm:hidden sm:pb-5">
|
||||
<div className="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
|
||||
<div className="rounded-lg p-2 shadow-lg sm:p-3" style={{ background: "#2F333D" }}>
|
||||
<div className="flex flex-wrap items-center justify-between">
|
||||
<div className="flex w-0 flex-1 items-center">
|
||||
<span className="bg-brand text-brandcontrast flex rounded-lg bg-opacity-30 p-2">
|
||||
<svg
|
||||
className="h-7 w-7 text-indigo-500 fill-current"
|
||||
className="h-7 w-7 fill-current text-indigo-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 50 50"
|
||||
enableBackground="new 0 0 50 50">
|
||||
@@ -29,16 +29,16 @@ export default function AddToHomescreen() {
|
||||
<path d="M35 40H15c-1.7 0-3-1.3-3-3V19c0-1.7 1.3-3 3-3h7v2h-7c-.6 0-1 .4-1 1v18c0 .6.4 1 1 1h20c.6 0 1-.4 1-1V19c0-.6-.4-1-1-1h-7v-2h7c1.7 0 3 1.3 3 3v18c0 1.7-1.3 3-3 3z" />
|
||||
</svg>
|
||||
</span>
|
||||
<p className="ml-3 text-xs font-medium text-white">
|
||||
<p className="text-xs font-medium text-white ltr:ml-3 rtl:mr-3">
|
||||
<span className="inline">{t("add_to_homescreen")}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
|
||||
<div className="order-2 flex-shrink-0 sm:order-3">
|
||||
<button
|
||||
onClick={() => setCloseBanner(true)}
|
||||
type="button"
|
||||
className="-mr-1 flex p-2 rounded-md hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
className="-mr-1 flex rounded-md p-2 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
<span className="sr-only">{t("dismiss")}</span>
|
||||
<XIcon className="h-6 w-6 text-white" aria-hidden="true" />
|
||||
</button>
|
||||
209
apps/web/components/CustomBranding.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
const brandColor = "#292929";
|
||||
const brandTextColor = "#ffffff";
|
||||
|
||||
export function colorNameToHex(color: string) {
|
||||
const colors = {
|
||||
aliceblue: "#f0f8ff",
|
||||
antiquewhite: "#faebd7",
|
||||
aqua: "#00ffff",
|
||||
aquamarine: "#7fffd4",
|
||||
azure: "#f0ffff",
|
||||
beige: "#f5f5dc",
|
||||
bisque: "#ffe4c4",
|
||||
black: "#000000",
|
||||
blanchedalmond: "#ffebcd",
|
||||
blue: "#0000ff",
|
||||
blueviolet: "#8a2be2",
|
||||
brown: "#a52a2a",
|
||||
burlywood: "#deb887",
|
||||
cadetblue: "#5f9ea0",
|
||||
chartreuse: "#7fff00",
|
||||
chocolate: "#d2691e",
|
||||
coral: "#ff7f50",
|
||||
cornflowerblue: "#6495ed",
|
||||
cornsilk: "#fff8dc",
|
||||
crimson: "#dc143c",
|
||||
cyan: "#00ffff",
|
||||
darkblue: "#00008b",
|
||||
darkcyan: "#008b8b",
|
||||
darkgoldenrod: "#b8860b",
|
||||
darkgray: "#a9a9a9",
|
||||
darkgreen: "#006400",
|
||||
darkkhaki: "#bdb76b",
|
||||
darkmagenta: "#8b008b",
|
||||
darkolivegreen: "#556b2f",
|
||||
darkorange: "#ff8c00",
|
||||
darkorchid: "#9932cc",
|
||||
darkred: "#8b0000",
|
||||
darksalmon: "#e9967a",
|
||||
darkseagreen: "#8fbc8f",
|
||||
darkslateblue: "#483d8b",
|
||||
darkslategray: "#2f4f4f",
|
||||
darkturquoise: "#00ced1",
|
||||
darkviolet: "#9400d3",
|
||||
deeppink: "#ff1493",
|
||||
deepskyblue: "#00bfff",
|
||||
dimgray: "#696969",
|
||||
dodgerblue: "#1e90ff",
|
||||
firebrick: "#b22222",
|
||||
floralwhite: "#fffaf0",
|
||||
forestgreen: "#228b22",
|
||||
fuchsia: "#ff00ff",
|
||||
gainsboro: "#dcdcdc",
|
||||
ghostwhite: "#f8f8ff",
|
||||
gold: "#ffd700",
|
||||
goldenrod: "#daa520",
|
||||
gray: "#808080",
|
||||
green: "#008000",
|
||||
greenyellow: "#adff2f",
|
||||
honeydew: "#f0fff0",
|
||||
hotpink: "#ff69b4",
|
||||
"indianred ": "#cd5c5c",
|
||||
indigo: "#4b0082",
|
||||
ivory: "#fffff0",
|
||||
khaki: "#f0e68c",
|
||||
lavender: "#e6e6fa",
|
||||
lavenderblush: "#fff0f5",
|
||||
lawngreen: "#7cfc00",
|
||||
lemonchiffon: "#fffacd",
|
||||
lightblue: "#add8e6",
|
||||
lightcoral: "#f08080",
|
||||
lightcyan: "#e0ffff",
|
||||
lightgoldenrodyellow: "#fafad2",
|
||||
lightgrey: "#d3d3d3",
|
||||
lightgreen: "#90ee90",
|
||||
lightpink: "#ffb6c1",
|
||||
lightsalmon: "#ffa07a",
|
||||
lightseagreen: "#20b2aa",
|
||||
lightskyblue: "#87cefa",
|
||||
lightslategray: "#778899",
|
||||
lightsteelblue: "#b0c4de",
|
||||
lightyellow: "#ffffe0",
|
||||
lime: "#00ff00",
|
||||
limegreen: "#32cd32",
|
||||
linen: "#faf0e6",
|
||||
magenta: "#ff00ff",
|
||||
maroon: "#800000",
|
||||
mediumaquamarine: "#66cdaa",
|
||||
mediumblue: "#0000cd",
|
||||
mediumorchid: "#ba55d3",
|
||||
mediumpurple: "#9370d8",
|
||||
mediumseagreen: "#3cb371",
|
||||
mediumslateblue: "#7b68ee",
|
||||
mediumspringgreen: "#00fa9a",
|
||||
mediumturquoise: "#48d1cc",
|
||||
mediumvioletred: "#c71585",
|
||||
midnightblue: "#191970",
|
||||
mintcream: "#f5fffa",
|
||||
mistyrose: "#ffe4e1",
|
||||
moccasin: "#ffe4b5",
|
||||
navajowhite: "#ffdead",
|
||||
navy: "#000080",
|
||||
oldlace: "#fdf5e6",
|
||||
olive: "#808000",
|
||||
olivedrab: "#6b8e23",
|
||||
orange: "#ffa500",
|
||||
orangered: "#ff4500",
|
||||
orchid: "#da70d6",
|
||||
palegoldenrod: "#eee8aa",
|
||||
palegreen: "#98fb98",
|
||||
paleturquoise: "#afeeee",
|
||||
palevioletred: "#d87093",
|
||||
papayawhip: "#ffefd5",
|
||||
peachpuff: "#ffdab9",
|
||||
peru: "#cd853f",
|
||||
pink: "#ffc0cb",
|
||||
plum: "#dda0dd",
|
||||
powderblue: "#b0e0e6",
|
||||
purple: "#800080",
|
||||
rebeccapurple: "#663399",
|
||||
red: "#ff0000",
|
||||
rosybrown: "#bc8f8f",
|
||||
royalblue: "#4169e1",
|
||||
saddlebrown: "#8b4513",
|
||||
salmon: "#fa8072",
|
||||
sandybrown: "#f4a460",
|
||||
seagreen: "#2e8b57",
|
||||
seashell: "#fff5ee",
|
||||
sienna: "#a0522d",
|
||||
silver: "#c0c0c0",
|
||||
skyblue: "#87ceeb",
|
||||
slateblue: "#6a5acd",
|
||||
slategray: "#708090",
|
||||
snow: "#fffafa",
|
||||
springgreen: "#00ff7f",
|
||||
steelblue: "#4682b4",
|
||||
tan: "#d2b48c",
|
||||
teal: "#008080",
|
||||
thistle: "#d8bfd8",
|
||||
tomato: "#ff6347",
|
||||
turquoise: "#40e0d0",
|
||||
violet: "#ee82ee",
|
||||
wheat: "#f5deb3",
|
||||
white: "#ffffff",
|
||||
whitesmoke: "#f5f5f5",
|
||||
yellow: "#ffff00",
|
||||
yellowgreen: "#9acd32",
|
||||
};
|
||||
|
||||
return colors[color.toLowerCase() as keyof typeof colors] !== undefined
|
||||
? colors[color.toLowerCase() as keyof typeof colors]
|
||||
: false;
|
||||
}
|
||||
|
||||
function computeContrastRatio(a: number[], b: number[]) {
|
||||
const lum1 = computeLuminance(a[0], a[1], a[2]);
|
||||
const lum2 = computeLuminance(b[0], b[1], b[2]);
|
||||
const brightest = Math.max(lum1, lum2);
|
||||
const darkest = Math.min(lum1, lum2);
|
||||
return (brightest + 0.05) / (darkest + 0.05);
|
||||
}
|
||||
|
||||
function computeLuminance(r: number, g: number, b: number) {
|
||||
const a = [r, g, b].map((v) => {
|
||||
v /= 255;
|
||||
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
||||
});
|
||||
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
||||
}
|
||||
|
||||
function hexToRGB(hex: string) {
|
||||
const color = hex.replace("#", "");
|
||||
return [parseInt(color.slice(0, 2), 16), parseInt(color.slice(2, 4), 16), parseInt(color.slice(4, 6), 16)];
|
||||
}
|
||||
|
||||
function getContrastingTextColor(bgColor: string | null): string {
|
||||
bgColor = bgColor == "" || bgColor == null ? brandColor : bgColor;
|
||||
const rgb = hexToRGB(bgColor);
|
||||
const whiteContrastRatio = computeContrastRatio(rgb, [255, 255, 255]);
|
||||
const blackContrastRatio = computeContrastRatio(rgb, [41, 41, 41]); //#292929
|
||||
return whiteContrastRatio > blackContrastRatio ? brandTextColor : brandColor;
|
||||
}
|
||||
|
||||
export function isValidHexCode(val: string | null) {
|
||||
if (val) {
|
||||
val = val.indexOf("#") === 0 ? val : "#" + val;
|
||||
const regex = new RegExp("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
|
||||
return regex.test(val);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function fallBackHex(val: string | null): string {
|
||||
if (val) if (colorNameToHex(val)) return colorNameToHex(val) as string;
|
||||
return brandColor;
|
||||
}
|
||||
|
||||
const BrandColor = ({ val = brandColor }: { val: string | undefined | null }) => {
|
||||
// ensure acceptable hex-code
|
||||
val = isValidHexCode(val) ? (val?.indexOf("#") === 0 ? val : "#" + val) : fallBackHex(val);
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty("--brand-color", val);
|
||||
document.documentElement.style.setProperty("--brand-text-color", getContrastingTextColor(val));
|
||||
}, [val]);
|
||||
return null;
|
||||
};
|
||||
|
||||
export default BrandColor;
|
||||
92
apps/web/components/DestinationCalendarSelector.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Select from "react-select";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import { trpc } from "@lib/trpc";
|
||||
|
||||
import Button from "@components/ui/Button";
|
||||
|
||||
interface Props {
|
||||
onChange: (value: { externalId: string; integration: string }) => void;
|
||||
isLoading?: boolean;
|
||||
hidePlaceholder?: boolean;
|
||||
/** The external Id of the connected calendar */
|
||||
value: string | undefined;
|
||||
}
|
||||
|
||||
const DestinationCalendarSelector = ({
|
||||
onChange,
|
||||
isLoading,
|
||||
value,
|
||||
hidePlaceholder,
|
||||
}: Props): JSX.Element | null => {
|
||||
const { t } = useLocale();
|
||||
const query = trpc.useQuery(["viewer.connectedCalendars"]);
|
||||
const [selectedOption, setSelectedOption] = useState<{ value: string; label: string } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedOption) {
|
||||
const selected = query.data?.connectedCalendars
|
||||
.map((connected) => connected.calendars ?? [])
|
||||
.flat()
|
||||
.find((cal) => cal.externalId === value);
|
||||
|
||||
if (selected) {
|
||||
setSelectedOption({
|
||||
value: `${selected.integration}:${selected.externalId}`,
|
||||
label: selected.name || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [query.data?.connectedCalendars, selectedOption, value]);
|
||||
|
||||
if (!query.data?.connectedCalendars.length) {
|
||||
return null;
|
||||
}
|
||||
const options =
|
||||
query.data.connectedCalendars.map((selectedCalendar) => ({
|
||||
key: selectedCalendar.credentialId,
|
||||
label: `${selectedCalendar.integration.title} (${selectedCalendar.primary?.name})`,
|
||||
options: (selectedCalendar.calendars ?? []).map((cal) => ({
|
||||
label: cal.name || "",
|
||||
value: `${cal.integration}:${cal.externalId}`,
|
||||
})),
|
||||
})) ?? [];
|
||||
return (
|
||||
<div className="relative">
|
||||
{/* There's no easy way to customize the displayed value for a Select, so we fake it. */}
|
||||
{!hidePlaceholder && (
|
||||
<div className="pointer-events-none absolute z-10">
|
||||
<Button size="sm" color="secondary" className="m-[1px] rounded-sm border-transparent">
|
||||
{t("select_destination_calendar")}: {selectedOption?.label || ""}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<Select
|
||||
name={"primarySelectedCalendar"}
|
||||
placeholder={!hidePlaceholder ? `${t("select_destination_calendar")}:` : undefined}
|
||||
options={options}
|
||||
isSearchable={false}
|
||||
className="focus:border-primary-500 focus:ring-primary-500 mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 sm:text-sm"
|
||||
onChange={(option) => {
|
||||
setSelectedOption(option);
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Split only the first `:`, since Apple uses the full URL as externalId */
|
||||
const [integration, externalId] = option.value.split(/:(.+)/);
|
||||
|
||||
onChange({
|
||||
integration,
|
||||
externalId,
|
||||
});
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
value={selectedOption}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DestinationCalendarSelector;
|
||||
@@ -6,7 +6,7 @@ export function Dialog(props: DialogProps) {
|
||||
const { children, ...other } = props;
|
||||
return (
|
||||
<DialogPrimitive.Root {...other}>
|
||||
<DialogPrimitive.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||
<DialogPrimitive.Overlay className="fixed inset-0 z-40 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||
{children}
|
||||
</DialogPrimitive.Root>
|
||||
);
|
||||
@@ -17,7 +17,7 @@ export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps
|
||||
({ children, ...props }, forwardedRef) => (
|
||||
<DialogPrimitive.Content
|
||||
{...props}
|
||||
className="min-w-[360px] fixed left-1/2 top-1/2 p-6 text-left bg-white rounded shadow-xl overflow-hidden -translate-x-1/2 -translate-y-1/2 sm:align-middle sm:w-full sm:max-w-lg"
|
||||
className="fixed left-1/2 top-1/2 z-50 min-w-[360px] -translate-x-1/2 -translate-y-1/2 rounded bg-white p-6 text-left shadow-xl sm:w-full sm:max-w-lg sm:align-middle"
|
||||
ref={forwardedRef}>
|
||||
{children}
|
||||
</DialogPrimitive.Content>
|
||||
@@ -32,10 +32,10 @@ type DialogHeaderProps = {
|
||||
export function DialogHeader(props: DialogHeaderProps) {
|
||||
return (
|
||||
<div className="mb-8">
|
||||
<h3 className="font-cal text-gray-900 text-lg font-bold leading-6" id="modal-title">
|
||||
<h3 className="leading-16 font-cal text-xl text-gray-900" id="modal-title">
|
||||
{props.title}
|
||||
</h3>
|
||||
{props.subtitle && <div className="text-gray-400 text-sm">{props.subtitle}</div>}
|
||||
{props.subtitle && <div className="text-sm text-gray-400">{props.subtitle}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export function DialogHeader(props: DialogHeaderProps) {
|
||||
export function DialogFooter(props: { children: ReactNode }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-5 flex space-x-2 justify-end">{props.children}</div>
|
||||
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse">{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,12 +13,12 @@ export default function EmptyScreen({
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-80 border border-dashed rounded-sm flex justify-center items-center flex-col my-6">
|
||||
<div className="bg-white w-[72px] h-[72px] flex justify-center items-center rounded-full">
|
||||
<Icon className="inline-block w-10 h-10 bg-white" />
|
||||
<div className="min-h-80 my-6 flex flex-col items-center justify-center rounded-sm border border-dashed">
|
||||
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-white">
|
||||
<Icon className="inline-block h-10 w-10 bg-white" />
|
||||
</div>
|
||||
<div className="max-w-[420px] text-center">
|
||||
<h2 className="text-lg font-medium mt-6 mb-1">{headline}</h2>
|
||||
<h2 className="mt-6 mb-1 text-lg font-medium">{headline}</h2>
|
||||
<p className="text-sm leading-6 text-gray-600">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,8 +38,8 @@ function CropContainer({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-40 h-40 rounded-full crop-container max-h-40">
|
||||
<div className="relative w-40 h-40 rounded-full">
|
||||
<div className="crop-container h-40 max-h-40 w-40 rounded-full">
|
||||
<div className="relative h-40 w-40 rounded-full">
|
||||
<Cropper
|
||||
image={imageSrc}
|
||||
crop={crop}
|
||||
@@ -110,7 +110,7 @@ export default function ImageUploader({
|
||||
(opened) => !opened && setFile(null) // unset file on close
|
||||
}>
|
||||
<DialogTrigger asChild>
|
||||
<div className="flex items-center px-3">
|
||||
<div className="flex items-center">
|
||||
<Button color="secondary" type="button" className="py-1 text-xs">
|
||||
{buttonMsg}
|
||||
</Button>
|
||||
@@ -119,38 +119,38 @@ export default function ImageUploader({
|
||||
<DialogContent>
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
||||
<h3 className="text-lg font-bold leading-6 text-gray-900 font-cal" id="modal-title">
|
||||
<h3 className="font-cal text-lg font-bold leading-6 text-gray-900" id="modal-title">
|
||||
{t("upload_target", { target })}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<div className="flex flex-col items-center justify-center p-8 mt-6 cropper bg-gray-50">
|
||||
<div className="cropper mt-6 flex flex-col items-center justify-center p-8">
|
||||
{!result && (
|
||||
<div className="flex items-center justify-start w-20 h-20 bg-gray-500 rounded-full max-h-20">
|
||||
<div className="flex h-20 max-h-20 w-20 items-center justify-start rounded-full bg-gray-50">
|
||||
{!imageSrc && (
|
||||
<p className="w-full text-sm text-center text-white sm:text-xs">
|
||||
<p className="w-full text-center text-sm text-white sm:text-xs">
|
||||
{t("no_target", { target })}
|
||||
</p>
|
||||
)}
|
||||
{imageSrc && <img className="w-20 h-20 rounded-full" src={imageSrc} alt={target} />}
|
||||
{imageSrc && <img className="h-20 w-20 rounded-full" src={imageSrc} alt={target} />}
|
||||
</div>
|
||||
)}
|
||||
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
|
||||
<label className="px-3 py-1 mt-8 text-xs font-medium leading-4 text-gray-700 bg-white border border-gray-300 rounded-sm hover:bg-gray-50 hover:text-gray-900 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-neutral-900 dark:bg-transparent dark:text-white dark:border-gray-800 dark:hover:bg-gray-900">
|
||||
<label className="mt-8 rounded-sm border border-gray-300 bg-white px-3 py-1 text-xs font-medium leading-4 text-gray-700 hover:bg-gray-50 hover:text-gray-900 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent dark:text-white dark:hover:bg-gray-900">
|
||||
<input
|
||||
onInput={onInputFile}
|
||||
type="file"
|
||||
name={id}
|
||||
placeholder={t("upload_image")}
|
||||
className="absolute mt-4 opacity-0 pointer-events-none"
|
||||
className="pointer-events-none absolute mt-4 opacity-0"
|
||||
accept="image/*"
|
||||
/>
|
||||
{t("choose_a_file")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse gap-x-2">
|
||||
<div className="mt-5 gap-x-2 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<DialogClose asChild>
|
||||
<Button onClick={() => showCroppedImage(croppedAreaPixels)}>{t("save")}</Button>
|
||||
</DialogClose>
|
||||
@@ -5,7 +5,7 @@ import classNames from "@lib/classNames";
|
||||
|
||||
export function List(props: JSX.IntrinsicElements["ul"]) {
|
||||
return (
|
||||
<ul {...props} className={classNames("sm:overflow-hidden rounded-sm sm:mx-0 -mx-4", props.className)}>
|
||||
<ul {...props} className={classNames("-mx-4 rounded-sm sm:mx-0 sm:overflow-hidden", props.className)}>
|
||||
{props.children}
|
||||
</ul>
|
||||
);
|
||||