diff --git a/.env.appStore.example b/.env.appStore.example index 667b5bf877ebe..886b3d3024a83 100644 --- a/.env.appStore.example +++ b/.env.appStore.example @@ -21,7 +21,8 @@ DAILY_SCALE_PLAN='' # - GOOGLE CALENDAR/MEET/LOGIN # Needed to enable Google Calendar integration and Login with Google # @see https://github.com/calendso/calendso#obtaining-the-google-api-credentials -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` diff --git a/.env.example b/.env.example index 506002099b895..fbddd79e4d58c 100644 --- a/.env.example +++ b/.env.example @@ -100,11 +100,13 @@ SEND_FEEDBACK_EMAIL= NEXT_PUBLIC_IS_E2E= # Used for internal billing system -NEXT_PUBLIC_STRIPE_PRO_PLAN_PRODUCT= NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE= NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE= NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE= STRIPE_WEBHOOK_SECRET= +STRIPE_PRO_PLAN_PRODUCT_ID= +STRIPE_PREMIUM_PLAN_PRODUCT_ID= +STRIPE_FREE_PLAN_PRODUCT_ID= # Use for internal Public API Keys and optional API_KEY_PREFIX=cal_ diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000000..bf537ca8bfa86 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,5 @@ +"♻️ autoupdate": + - apps/web/public/static/locales/**/*.json + +automerge: + - apps/web/public/static/locales/**/*.json diff --git a/.github/workflows/bug-hunting.yml b/.github/workflows/bug-hunting.yml new file mode 100644 index 0000000000000..bea2ffac437a3 --- /dev/null +++ b/.github/workflows/bug-hunting.yml @@ -0,0 +1,22 @@ +name: Add bugs to Bug Hunting + +on: + issues: + types: + - opened + - labeled + pull_request: + types: + - opened + - labeled + +jobs: + bug-hunting: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v0.1.0 + with: + project-url: https://github.com/orgs/calcom/projects/1 + github-token: ${{ secrets.GH_ACCESS_TOKEN }} + labeled: '🐛 bug' diff --git a/.github/workflows/check-types.yml b/.github/workflows/check-types.yml index a8ff5afd1b680..6147355fce251 100644 --- a/.github/workflows/check-types.yml +++ b/.github/workflows/check-types.yml @@ -1,10 +1,12 @@ name: Check types on: - pull_request_target: + pull_request: branches: - main + paths: + - '**.tsx?' jobs: - types: + check-types: name: Check types strategy: matrix: diff --git a/.github/workflows/cron-bookingReminder.yml b/.github/workflows/cron-bookingReminder.yml index 9f6abc1f9a3c7..7f7d461819fdb 100644 --- a/.github/workflows/cron-bookingReminder.yml +++ b/.github/workflows/cron-bookingReminder.yml @@ -7,7 +7,7 @@ on: # Runs “At minute 0, 15, 30, and 45.” (see https://crontab.guru) - cron: "0,15,30,45 * * * *" jobs: - cron: + cron-bookingReminder: env: APP_URL: ${{ secrets.APP_URL }} CRON_API_KEY: ${{ secrets.CRON_API_KEY }} diff --git a/.github/workflows/cron-downgradeUsers.yml b/.github/workflows/cron-downgradeUsers.yml index 3706f57120803..8e3b9411b87b7 100644 --- a/.github/workflows/cron-downgradeUsers.yml +++ b/.github/workflows/cron-downgradeUsers.yml @@ -7,7 +7,7 @@ on: # Runs “At minute 0, 15, 30, and 45.” (see https://crontab.guru) - cron: "0,15,30,45 * * * *" jobs: - cron: + cron-downgradeUsers: env: APP_URL: ${{ secrets.APP_URL }} CRON_API_KEY: ${{ secrets.CRON_API_KEY }} diff --git a/.github/workflows/e2e-embed.yml b/.github/workflows/e2e-embed.yml index 51d75b40a7f09..14d07dfb01b1b 100644 --- a/.github/workflows/e2e-embed.yml +++ b/.github/workflows/e2e-embed.yml @@ -1,20 +1,14 @@ -name: E2E test +name: E2E tests Embed on: - pull_request_target: # So we can test on forks + pull_request: # So we can test on forks branches: - main # Embed e2e - tests verify booking flow which is applicable to non-embed case also. So, don't ignore apps/web changes. - paths-ignore: - - apps/api/** - - apps/console/** - - apps/docs/** - - apps/swagger/** - - apps/website/** - - apps/web/public/** - - tests/** - - playwright/** + paths: + - apps/web/** + - packages/embeds/** jobs: - test: + e2e-embed: timeout-minutes: 20 name: Embed and booking flow(for non-embed as well) strategy: @@ -33,6 +27,9 @@ jobs: # CRON_API_KEY: xxx CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }} NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }} + NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }} + NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }} + NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }} STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }} STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }} STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }} @@ -89,9 +86,8 @@ jobs: - name: Install playwright deps # if: steps.playwright-cache.outputs.cache-hit != 'true' run: yarn playwright install --with-deps - - run: yarn embed-tests-prepare - - run: yarn workspace @calcom/embed-core embed-tests-update-snapshots:ci - - run: yarn workspace @calcom/embed-react embed-tests-update-snapshots:ci + - name: Run Tests + run: yarn turbo run embed-tests-update-snapshots:ci --scope=@calcom/embed-react --concurrency=1 - name: Upload embed-core results if: ${{ always() }} diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0dfd916e6786f..db6c2569354ba 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,12 +1,13 @@ name: E2E test on: - pull_request_target: # So we can test on forks + pull_request: # So we can test on forks branches: - main - paths-ignore: - - apps/web/public/static/locales/** + paths: + - apps/web/** + - packages/** jobs: - test: + e2e: timeout-minutes: 20 name: Testing ${{ matrix.node }} and ${{ matrix.os }} strategy: @@ -25,9 +26,15 @@ jobs: # CRON_API_KEY: xxx CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }} NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }} + NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }} + NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }} + NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }} STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }} STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }} STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }} + STRIPE_PRO_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PRO_PLAN_PRODUCT_ID }} + STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PREMIUM_PLAN_PRODUCT_ID }} + STRIPE_FREE_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_FREE_PLAN_PRODUCT_ID }} PAYMENT_FEE_PERCENTAGE: 0.005 PAYMENT_FEE_FIXED: 10 SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000000..2f10275dfe5f2 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,14 @@ +name: "Pull Request Labeler" +on: + - pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 637fe31ded228..c2310c11cab89 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,8 +1,11 @@ name: Lint on: - pull_request_target: + pull_request: branches: - main + paths: + - '**.tsx?' + - '**.jsx?' jobs: lint: strategy: diff --git a/.github/workflows/required-checks.yml b/.github/workflows/required-checks.yml new file mode 100644 index 0000000000000..ff8dc301b8c01 --- /dev/null +++ b/.github/workflows/required-checks.yml @@ -0,0 +1,40 @@ +name: "Meta Workflow: Require Conditional Status Checks" +on: + pull_request: + branches: + - main +jobs: + required-checks: + strategy: + matrix: + node: ["16.x"] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Ensure All Conditional Checks Have Passed + uses: blend/require-conditional-status-checks@2022.02.04 + with: + timeout: 15m + github-token: ${{ github.token }} + interval: 20s + # Question marks aren't working + # @see https://github.com/blend/require-conditional-status-checks/pull/11 + checks-yaml: | + - job: lint + paths: + - /**/*.jsx + - /**/*.js + - /**/*.tsx + - /**/*.ts + - job: check-types + paths: + - /**/*.tsx + - /**/*.ts + - job: e2e + paths: + - /apps/web/** + - /packages/** + - job: e2e-embed + paths: + - /apps/web/** + - /packages/embeds/** diff --git a/.gitignore b/.gitignore index 3df22db2607ca..a99226a7833de 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,7 @@ dist # Linting lint-results + +# Snaplet +.snaplet/snapshots +.snaplet/structure.d.ts diff --git a/.husky/pre-commit b/.husky/pre-commit index d2ae35e84b09c..c6a7938b7c5a1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,3 +2,5 @@ . "$(dirname "$0")/_/husky.sh" yarn lint-staged + +yarn app-store:build && git add packages/app-store/*.generated.* diff --git a/.snaplet/config.json b/.snaplet/config.json new file mode 100644 index 0000000000000..6322eabfa62f4 --- /dev/null +++ b/.snaplet/config.json @@ -0,0 +1,4 @@ +{ + "projectId": "cl4u26bwz7962859ply7ibuo43t", + "databaseUrl": "postgresql://postgres@localhost:5450/calendso" +} diff --git a/.snaplet/manifest.json b/.snaplet/manifest.json new file mode 100644 index 0000000000000..dfcc3af19b23a --- /dev/null +++ b/.snaplet/manifest.json @@ -0,0 +1,3 @@ +{ + "version": "0.3.0" +} diff --git a/.snaplet/transform.ts b/.snaplet/transform.ts new file mode 100644 index 0000000000000..b229acabcbdf4 --- /dev/null +++ b/.snaplet/transform.ts @@ -0,0 +1,97 @@ +// This transform config was generated by Snaplet. +// Snaplet found fields that may contain personally identifiable information (PII) +// and used that to populate this file. +import { copycat as c } from "@snaplet/copycat"; + +import type { Transform } from "./structure"; + +function hasStringProp(x: unknown, key: T): x is { [key in T]: string } { + return !!x && typeof x === "object" && key in x; +} + +function replaceKeyIfExists(x: object, key: T) { + if (hasStringProp(x, key)) { + return { ...x, [key]: c.uuid(x[key]) }; + } + return x; +} + +function generateSlug(x: string) { + return c.words(x, { max: 3 }).split(" ").join("-"); +} + +function replaceSensitiveKeys(record: object) { + return { + ...record, + ...replaceKeyIfExists(record, "client_id"), + ...replaceKeyIfExists(record, "client_secret"), + ...replaceKeyIfExists(record, "public_key"), + ...replaceKeyIfExists(record, "api_key"), + ...replaceKeyIfExists(record, "signing_secret"), + ...replaceKeyIfExists(record, "access_token"), + ...replaceKeyIfExists(record, "refresh_token"), + ...replaceKeyIfExists(record, "stripe_user_id"), + ...replaceKeyIfExists(record, "stripe_publishable_key"), + ...replaceKeyIfExists(record, "accessToken"), + ...replaceKeyIfExists(record, "refreshToken"), + ...replaceKeyIfExists(record, "bot_user_id"), + ...replaceKeyIfExists(record, "app_id"), + }; +} + +const generateUsername = (x: string) => `${c.firstName(x)}-${c.lastName(x)}${c.int(x, { min: 2, max: 99 })}`; + +const config: Transform = () => ({ + public: { + ApiKey: ({ row }) => ({ + hashedKey: c.uuid(row.hashedKey), + }), + App: ({ row }) => ({ + keys: replaceSensitiveKeys(row.keys), + }), + Attendee: ({ row }) => ({ + email: c.email(row.email), + name: c.fullName(row.name), + timeZone: c.timezone(row.timeZone), + }), + Credential: ({ row }) => ({ + key: typeof row.key === "string" ? c.uuid(row.key) : replaceSensitiveKeys(row.key), + }), + EventType: ({ row }) => ({ + slug: generateSlug(row.slug), + timeZone: c.timezone(row.timeZone), + eventName: c.words(row.eventName, { max: 3 }), + }), + ResetPasswordRequest: ({ row }) => ({ + email: c.email(row.email), + }), + Schedule: ({ row }) => ({ + timeZone: c.timezone(row.timeZone), + }), + Team: ({ row }) => ({ + bio: c.sentence(row.bio), + name: c.words(row.name, { max: 2 }), + slug: generateSlug(row.slug), + }), + users: ({ row }) => + row.role !== "ADMIN" + ? { + bio: c.sentence(row.bio), + email: c.email(row.email), + name: c.fullName(row.name), + password: c.password(row.password), + timeZone: c.timezone(row.timeZone), + username: generateUsername(row.username), + } + : row, + VerificationToken: ({ row }) => ({ + token: c.uuid(row.token), + }), + Account: ({ row }) => ({ + access_token: c.uuid(row.access_token), + refresh_token: c.uuid(row.refresh_token), + }), + }, +}); + +export default config; diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 56a9a8bc2c06c..eb7956c6ae47f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b79473e2185ad..249487423dfd0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Cal.com -Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. +Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. - Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission. @@ -8,22 +8,19 @@ Contributions are what make the open source community such an amazing place to b ### Legend -✅ = has knowledge +✅ = has knowledge 🥇 = is their main priority -⚠️ = is the only one with knowledge +⚠️ = is the only one with knowledge -👀 = has no knowledge but wants to be onboarded +👀 = has no knowledge but wants to be onboarded Areas of expertise table - - - ## Developing The development branch is `main`. This is the branch that all pull diff --git a/README.md b/README.md index 516e9fe60b90b..567b6feff66d6 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ ## About The Project -booking-screen +booking-screen # Scheduling infrastructure for absolutely everyone @@ -94,7 +94,7 @@ Here is what you need to be able to run Cal. ### Setup -1. Clone the repo into a public GitHub repository (to comply with AGPLv3. To clone in a private repository, [acquire a commercial license](https://cal.com/sales)) +1. Clone the repo into a public GitHub repository (or fork https://github.com/calcom/cal.com/fork). If you plan to distribute the code, keep the source code public to comply with [AGPLv3](https://github.com/calcom/cal.com/blob/main/LICENSE). To clone in a private repository, [acquire a commercial license](https://cal.com/sales)) ```sh git clone https://github.com/calcom/cal.com.git @@ -281,8 +281,11 @@ You can deploy Cal on [Railway](https://railway.app/) using the button above. Th ## Roadmap + + Cal.com Roadmap + -See the [roadmap project](https://github.com/orgs/calcom/projects/1) for a list of proposed features (and known issues). You can change the view to see planned tagged releases. +See the [roadmap project](https://cal.com/roadmap) for a list of proposed features (and known issues). You can change the view to see planned tagged releases. @@ -437,7 +440,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/) - - Jitsu.com + +Jitsu.com Cal.com is an [open startup](https://cal.com/open) and [Jitsu](https://github.com/jitsucom/jitsu) (an open-source Segment alternative) helps us to track most of the usage metrics. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..45e909fe464d1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security +Contact: security@cal.com + +Based on [https://supabase.com/.well-known/security.txt](https://supabase.com/.well-known/security.txt) + +At Cal.com, we consider the security of our systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present. + +If you discover a vulnerability, we would like to know about it so we can take steps to address it as quickly as possible. We would like to ask you to help us better protect our clients and our systems. + +## Out of scope vulnerabilities: + +* Clickjacking on pages with no sensitive actions. +* Unauthenticated/logout/login CSRF. +* Attacks requiring MITM or physical access to a user's device. +* Any activity that could lead to the disruption of our service (DoS). +* Content spoofing and text injection issues without showing an attack vector/without being able to modify HTML/CSS. +* Email spoofing +* Missing DNSSEC, CAA, CSP headers +* Lack of Secure or HTTP only flag on non-sensitive cookies +* Deadlinks + +## Please do the following: + +* E-mail your findings to [security@cal.com](mailto:security@cal.com). +* Do not run automated scanners on our infrastructure or dashboard. If you wish to do this, contact us and we will set up a sandbox for you. +* Do not take advantage of the vulnerability or problem you have discovered, for example by downloading more data than necessary to demonstrate the vulnerability or deleting or modifying other people's data, +* Do not reveal the problem to others until it has been resolved, +* Do not use attacks on physical security, social engineering, distributed denial of service, spam or applications of third parties, +* Do provide sufficient information to reproduce the problem, so we will be able to resolve it as quickly as possible. Usually, the IP address or the URL of the affected system and a description of the vulnerability will be sufficient, but complex vulnerabilities may require further explanation. + +## What we promise: + +* We will respond to your report within 3 business days with our evaluation of the report and an expected resolution date, +* If you have followed the instructions above, we will not take any legal action against you in regard to the report, +* We will handle your report with strict confidentiality, and not pass on your personal details to third parties without your permission, +* We will keep you informed of the progress towards resolving the problem, +* In the public information concerning the problem reported, we will give your name as the discoverer of the problem (unless you desire otherwise), and +* We strive to resolve all problems as quickly as possible, and we would like to play an active role in the ultimate publication on the problem after it is resolved. diff --git a/app.json b/app.json index 75190ec814609..3f91f1b1a3d46 100644 --- a/app.json +++ b/app.json @@ -18,7 +18,11 @@ "description": "Application Key for symmetric encryption and decryption. Must be 32 bytes for AES256 encryption algorithm.", "value": "secret" }, - "NEXTAUTH_SECRET": "secret" + "NEXTAUTH_SECRET": "secret", + "NEXTAUTH_URL": { + "description": "Replace HEROKU_APP_NAME with the name given to your app", + "value": "https://HEROKU_APP_NAME.herokuapp.com" + } }, "scripts": { "postdeploy": "cd packages/prisma && npx prisma migrate deploy" diff --git a/apps/docs/pages/self-hosting/vercel.mdx b/apps/docs/pages/self-hosting/vercel.mdx index a5341240db7a8..969d25b32dc2d 100644 --- a/apps/docs/pages/self-hosting/vercel.mdx +++ b/apps/docs/pages/self-hosting/vercel.mdx @@ -18,7 +18,7 @@ You need a PostgresDB database hosted somewhere. [Heroku](https://www.heroku.com git clone https://github.com//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)) +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-setup) and [Obtaining the Google API Credentials](https://github.com/calcom/cal.com#obtaining-the-google-api-credentials)) 3. Install packages with `yarn` diff --git a/apps/docs/theme.config.js b/apps/docs/theme.config.js index 935c26a76cfeb..25857c7491970 100644 --- a/apps/docs/theme.config.js +++ b/apps/docs/theme.config.js @@ -1,3 +1,5 @@ +import { SEO_IMG_DEFAULT, DOCS_URL } from "@calcom/lib/constants"; + const themeConfig = { github: "https://github.com/calcom/cal.com", docsRepositoryBase: "https://github.com/calcom/cal.com/blob/main/apps/docs/pages", @@ -18,11 +20,11 @@ const themeConfig = { content="Explore advice and explanations for all of our features, and discover new tips and tricks to get the most out of your subscription." /> - + - + - + diff --git a/apps/storybook/.gitkeep b/apps/storybook/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/apps/web/components/AdditionalCalendarSelector.tsx b/apps/web/components/AdditionalCalendarSelector.tsx index 42f82f27435af..4a19957229ee1 100644 --- a/apps/web/components/AdditionalCalendarSelector.tsx +++ b/apps/web/components/AdditionalCalendarSelector.tsx @@ -65,6 +65,10 @@ const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorPro return { ...defaultStyles, borderRadius: "2px", + "@media only screen and (min-width: 640px)": { + ...(defaultStyles["@media only screen and (min-width: 640px)"] as object), + maxWidth: "320px", + }, }; }, }} diff --git a/apps/web/components/DestinationCalendarSelector.tsx b/apps/web/components/DestinationCalendarSelector.tsx index 414073918c2a5..746d352a630d3 100644 --- a/apps/web/components/DestinationCalendarSelector.tsx +++ b/apps/web/components/DestinationCalendarSelector.tsx @@ -89,6 +89,10 @@ const DestinationCalendarSelector = ({ return { ...defaultStyles, borderRadius: "2px", + "@media only screen and (min-width: 640px)": { + ...(defaultStyles["@media only screen and (min-width: 640px)"] as object), + maxWidth: "320px", + }, }; }, }} diff --git a/apps/web/components/Embed.tsx b/apps/web/components/Embed.tsx index 2c92492da9a22..dff294bcf5148 100644 --- a/apps/web/components/Embed.tsx +++ b/apps/web/components/Embed.tsx @@ -467,12 +467,14 @@ const tabs = [ } return ( <> - {t("place_where_cal_widget_appear")} +
+ {t("place_where_cal_widget_appear")} +
+
+ +
+ +
- -
-
- - -
- { - avatarRef.current.value = newAvatar; - const nativeInputValueSetter = Object.getOwnPropertyDescriptor( - window.HTMLInputElement.prototype, - "value" - )?.set; - nativeInputValueSetter?.call(avatarRef.current, newAvatar); - const ev2 = new Event("input", { bubbles: true }); - avatarRef.current.dispatchEvent(ev2); - updateProfileHandler(ev2 as unknown as FormEvent); - setImageSrc(newAvatar); - }} +
+
+ + +
+ { + avatarRef.current.value = newAvatar; + const nativeInputValueSetter = Object.getOwnPropertyDescriptor( + window.HTMLInputElement.prototype, + "value" + )?.set; + nativeInputValueSetter?.call(avatarRef.current, newAvatar); + const ev2 = new Event("input", { bubbles: true }); + avatarRef.current.dispatchEvent(ev2); + updateProfileHandler(ev2 as unknown as FormEvent); + setImageSrc(newAvatar); + }} + imageSrc={imageSrc} + /> +
+
-
-
-
- -
- v && setSelectedTimeFormat(v)} - className="mt-1 block w-full rounded-sm capitalize shadow-sm sm:text-sm" - options={timeFormatOptions} - /> -
-
-
- -
- v && setSelectedLanguage(v)} + className="mt-1 block w-full rounded-sm capitalize shadow-sm sm:text-sm" + options={localeOptions} + /> +
-
-
-
- +
+ +
+ v && setSelectedTimeZone(v)} + className="mt-1 block w-full rounded-sm shadow-sm sm:text-sm" + /> +
-
-