Compare commits

...
36 Commits
Author SHA1 Message Date
Keith Williams f8f6c31e40 chore: v4.6.24 (#17639)
release.yml / release (push) Canceled after 0s
2024-11-14 18:06:09 -03:00
Anik Dhabal Babu 7246fa4084 fix: unable to update host schedules (#17649) 2024-11-14 15:37:19 -05:00
Benny Joo 039a0b7a85 chore: remove wrong logs (#17648) 2024-11-14 18:57:51 +00:00
sean-brydon 12c5005305 chore: routingform org attribute seed (#17510)
* seed to org

* more org+routing form seed improvments

* add routing responses

* check if attributes already exist to prevent crash

* remove files not for PR

* fix type error

* fix connection

* assign manually

* fix seed

* update to match integration tests

* fix integration test to new user count
2024-11-14 14:50:26 -03:00
Sachin Siddhuandunknown 1ff6465384 fix: resolved troubleshoot-sidbar bug (#17613)
* resolved troubleshoot-sidbar bug

* fulfilled review changes

---------

Co-authored-by: unknown <sachinsiddhu112@gmail.com>
2024-11-14 13:26:55 -03:00
ae706bb6d6 feat: update translations via @replexica (#17629)
* feat: update translations via @replexica

* feat: update translations via @replexica

* Delete packages/ui/components/data-table/tanstack.d.ts

* Delete packages/lib/sync/services/CloseComService.ts

* Delete packages/lib/sync/SyncServiceManager.ts

---------

Co-authored-by: Replexica <support@replexica.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-11-14 16:19:03 +00:00
Lauris Skraucis 538a39328e fix: useOAuthClient is not initialized (#17637) 2024-11-14 15:35:45 +00:00
Joe Au-Yeung 3589767099 feat: Salesforce when create contacts under an account if creating leads is chosen [CAL-4713] (#17630) 2024-11-14 10:29:21 -05:00
Kartik SainiandUdit Takkar ff2754f663 feat: allow marking no show after booking has started (#17625)
* feat: allow marking no show after booking has started

* fix

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-11-14 09:55:39 +00:00
Rajiv Sahal 65484e7d01 fix: BookerEmbed atom localStorage issues (#17611) 2024-11-14 08:07:47 +00:00
Peer Richelsen 4d942a454a chore: typo in webhook (#17628) 2024-11-14 02:57:03 +00:00
Keith WilliamsandUdit Takkar 7dbcb62724 perf: Move /me stats to separate tRPC handler (#17206)
* perf: Move /me stats to separate tRPC handler

* Update packages/trpc/server/routers/loggedInViewer/meStats.handler.ts

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>

* Rename and skipping batch for myStats

* Refactor of counting team events

* Fixed type issues

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-11-13 20:55:57 -03:00
Benny Joo c197c33fd0 chore: upgrade @vercel/og lib (#17503)
## 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. -->

- housekeeping: having important packages up to date

<!-- Please provide a loom video for visual changes to speed up reviews
 Loom Video: https://www.loom.com/
-->

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] N/A - I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## 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. Write details that help to start the tests -->

- Are there environment variables that should be set?
- What are the minimal test data to have?
- What is expected (happy path) to have (input and output)?
- Any other important info that could help to test that PR

## Checklist

<!-- Remove bullet points below that don't apply to you -->

- I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code doesn't follow the style guidelines of this project
- I haven't commented my code, particularly in hard-to-understand areas
- I haven't checked if my changes generate no new warnings
2024-11-13 13:50:21 -07:00
Keith Williams 815065d67c feat: Add API v2 logs to axiom (#17595)
## What does this PR do?

Adds ability to send API v2 logs to Axiom.

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] N/A - I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

- Add the AXIOM_DATASET and AXIOM_TOKEN variables and run the API locally. Ensure the logs flow through to Axiom.
2024-11-13 13:18:53 -07:00
Omar López 02cecd6707 chore: Cleanup Close.com (#16929) 2024-11-13 15:14:31 -05:00
Keith Williams 81386d4ec0 chore: v4.6.23 (#17620)
release.yml / release (push) Canceled after 0s
2024-11-13 14:40:22 -03:00
Eunjae LeeandKeith Williams 204e411585 fix: make actions column sticky in members list (#17554)
* fix: make actions column sticky in members list

* clean up import

* change type definition

* remove old export

* include tanstack.d.ts

* fix declaration file

* move type def to packages/types/tanstack-table.d.ts

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-11-13 16:36:01 +00:00
Chiranjeev VishnoiandAnik Dhabal Babu 1ec1554cb5 change telly url (#17618)
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-11-13 16:21:53 +00:00
Udit Takkar 241579eba6 refactor: change title (#17623)
* chore: change title

* chore: translation
2024-11-13 16:19:58 +00:00
Udit Takkar 8ccad29ab6 fix: skip triggering webhook in case of duplicate email (#17612)
* fix: skip sending webhook in case of duplicate response

* fix: type err

* fix: tests

* refactor: only check email

* fix: type err

* chore: changed it to 60 min

* fix: use lowercase
2024-11-13 15:50:26 +00:00
74b4d7a94a chore: Automated API v2 OpenAPI spec generation (#17046)
* chore: Automated API v2 OpenAPI spec generation

* chore: update docs

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Morgan Vernay <morgan@cal.com>
2024-11-13 15:28:25 +00:00
5c6e60b726 fix: fetch next batch if event types are empty and cursor exists (#17109)
* fix: fetch next batch if event types are empty and cursor exists

* refactor: improve

* fix: add isFetchingForFirstTime

* chore: add number type

* fix: type err

* chore: add logs

* fix: type err

* fix: conflict

* fix: bug

* fix: type err

* chore: try changing type

* chore: add nul

* Update packages/trpc/server/routers/viewer/eventTypes/getEventTypesFromGroup.handler.ts

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>

* chore: use log.info

---------

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2024-11-13 14:37:03 +00:00
Alex van Andel 18c7c3c940 fix: Refactor publicPageUrl to use getBookerBaseUrlSync like elsewhere (#17607) 2024-11-13 08:55:01 -05:00
fbd113b976 feat: update translations via @replexica (#17619)
* feat: update translations via @replexica

* feat: update translations via @replexica

* feat: update translations via @replexica

---------

Co-authored-by: Replexica <support@replexica.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-11-13 13:53:51 +00:00
Udit Takkar c7f11c6795 fix: mark guest are no show (#17588)
* fix: mark guest are no show

* chore: missing import

* nit

* fix: type err
2024-11-13 19:03:55 +05:30
Peer Richelsen 84fb9bb371 chore: update Instant Meeting Error Message (#17617)
* Update common.json

* small copy changes
2024-11-13 13:08:05 +00:00
Lauris Skraucis 1aac70f643 feat: v2 confirm / decline booking endpoints (#17578)
* feat: v2 confirm / decline booking endpoints

* chore: bump platform libraries

* fix: type export

* tests: accepting and declining a booking

* refactor: sent emails abstract renderEmail with getHtml that is mocked in test
2024-11-13 11:20:43 +02:00
Lauris Skraucis 0dde8c1db9 feat: v2 multiple length event types and their bookings (#17598)
* feat: input lengthInMinutesOptions

* Revert "feat: input lengthInMinutesOptions"

This reverts commit f23fd8a3861097f0972cc6210b47f25511d85183.

* feat: handle lengthInMinutesOptions input

* feat: handle lengthInMinutesOptions event output

* fix: remove it.only

* feat: variable length bookings
2024-11-13 11:13:11 +02:00
Ankit YadavandOmar López 0da3a9fa11 fix: #17602 (#17604)
Co-authored-by: Omar López <zomars@me.com>
2024-11-12 20:20:38 +00:00
Alex van Andel eb8f5bd194 chore: Release v4.6.22 (#17600)
release.yml / release (push) Canceled after 0s
2024-11-12 18:18:37 +00:00
Morgan 82901fee94 fix: apiv2 updateNewTeamMemberEventTypes silently (#17555)
* fix: apiv2 updateNewTeamMemberEventTypes silently

* fixup! fix: apiv2 updateNewTeamMemberEventTypes silently
2024-11-12 09:32:21 -03:00
Udit Takkar 4e0e3a47f5 perf: routing forms loading time (#17518)
* perf: routing forms loading time

* chore: add TODO

* chore

* chore: add type

* chore: use Promise.all

* fix: type err

* fix: fetch id

* refactor: don't fetch team

* chore: add name
2024-11-12 17:32:42 +05:30
Syed Ali Shahbaz dc400d80d0 fix: split firstname lastname support, phone support & timezone specific startTime in success redirect params (#17593)
* init

* fixes

* fix type
2024-11-12 11:16:41 +00:00
Morgan 6889592d4f feat: add free platform plan (#17581)
* feat: add free platform plan

* chore: handle payment success / fail overdue

* chore: refactor and add tests
2024-11-12 11:14:51 +02:00
Benny Joo 95b833bc1c fix: avatars are not showing in preview image (#17592) 2024-11-12 07:57:06 +00:00
b06683458a feat: update translations via @replexica (#17585)
Co-authored-by: Replexica <support@replexica.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-11-11 22:20:17 -03:00
146 changed files with 4602 additions and 8533 deletions
@@ -81,7 +81,7 @@ describe("retrieveScopedAccessibleUsers tests", () => {
where: { email: "member2-acme@example.com" },
});
expect(accessibleUserIds.length).toBe(3);
expect(accessibleUserIds.length).toBe(11);
expect(accessibleUserIds).toContain(memberOneUser.id);
expect(accessibleUserIds).toContain(memberTwoUser.id);
expect(accessibleUserIds).toContain(adminUser.id);
+4
View File
@@ -28,3 +28,7 @@ API_KEY_PREFIX=cal_
GET_LICENSE_KEY_URL="https://console.cal.com/api/license"
IS_E2E=false
DOCS_URL=
# Axiom logging
AXIOM_DATASET=
AXIOM_TOKEN=
+4 -2
View File
@@ -26,9 +26,10 @@
"copy-swagger-module": "ts-node -r tsconfig-paths/register swagger/copy-swagger-module.ts"
},
"dependencies": {
"@axiomhq/winston": "^1.2.0",
"@calcom/platform-constants": "*",
"@calcom/platform-enums": "*",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.57",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.60",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
@@ -69,7 +70,8 @@
"rxjs": "^7.8.1",
"stripe": "^15.3.0",
"uuid": "^8.3.2",
"winston": "^3.11.0",
"winston": "^3.13.0",
"winston-transport": "^4.7.0",
"zod": "^3.22.4"
},
"devDependencies": {
@@ -53,6 +53,7 @@ import {
CreateBookingInput_2024_08_13,
CreateInstantBookingInput_2024_08_13,
CreateRecurringBookingInput_2024_08_13,
DeclineBookingInput_2024_08_13,
} from "@calcom/platform-types";
@Controller({
@@ -281,4 +282,51 @@ export class BookingsController_2024_08_13 {
data: booking,
};
}
@Post("/:bookingUid/confirm")
@HttpCode(HttpStatus.OK)
@Permissions([BOOKING_WRITE])
@UseGuards(ApiAuthGuard, BookingUidGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
@ApiOperation({ summary: "Confirm booking that requires a confirmation" })
async confirmBooking(
@Param("bookingUid") bookingUid: string,
@GetUser() user: UserWithProfile
): Promise<GetBookingOutput_2024_08_13> {
const booking = await this.bookingsService.confirmBooking(bookingUid, user);
return {
status: SUCCESS_STATUS,
data: booking,
};
}
@Post("/:bookingUid/decline")
@HttpCode(HttpStatus.OK)
@Permissions([BOOKING_WRITE])
@UseGuards(ApiAuthGuard, BookingUidGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
@ApiOperation({ summary: "Decline booking that requires a confirmation" })
async declineBooking(
@Param("bookingUid") bookingUid: string,
@Body() body: DeclineBookingInput_2024_08_13,
@GetUser() user: UserWithProfile
): Promise<GetBookingOutput_2024_08_13> {
const booking = await this.bookingsService.declineBooking(bookingUid, user, body.reason);
return {
status: SUCCESS_STATUS,
data: booking,
};
}
}
@@ -0,0 +1,262 @@
import { bootstrap } from "@/app";
import { AppModule } from "@/app.module";
import { CreateBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/create-booking.output";
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { User } from "@prisma/client";
import * as request from "supertest";
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withApiAuth } from "test/utils/withApiAuth";
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
import {
AttendeeScheduledEmail,
OrganizerScheduledEmail,
AttendeeDeclinedEmail,
} from "@calcom/platform-libraries";
import { BookingOutput_2024_08_13, GetBookingOutput_2024_08_13 } from "@calcom/platform-types";
import { Booking, PlatformOAuthClient, Team } from "@calcom/prisma/client";
jest.spyOn(AttendeeScheduledEmail.prototype as any, "getHtml").mockImplementation(async function () {
return "<html><body>Mocked Email Content</body></html>";
});
jest.spyOn(OrganizerScheduledEmail.prototype as any, "getHtml").mockImplementation(async function () {
return "<html><body>Mocked Email Content</body></html>";
});
jest.spyOn(AttendeeDeclinedEmail.prototype as any, "getHtml").mockImplementation(async function () {
return "<html><body>Mocked Email Content</body></html>";
});
describe("Bookings Endpoints 2024-08-13", () => {
describe("Bookings confirmation", () => {
let app: INestApplication;
let organization: Team;
let userRepositoryFixture: UserRepositoryFixture;
let bookingsRepositoryFixture: BookingsRepositoryFixture;
let schedulesService: SchedulesService_2024_04_15;
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
let oAuthClient: PlatformOAuthClient;
let teamRepositoryFixture: TeamRepositoryFixture;
const userEmail = "bookings-controller-e2e@api.com";
let user: User;
let eventTypeId: number;
const eventTypeSlug = "peer-coding";
let createdBooking1: Booking;
let createdBooking2: Booking;
beforeAll(async () => {
const moduleRef = await withApiAuth(
userEmail,
Test.createTestingModule({
imports: [AppModule, PrismaModule, UsersModule, SchedulesModule_2024_04_15],
})
)
.overrideGuard(PermissionsGuard)
.useValue({
canActivate: () => true,
})
.compile();
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
bookingsRepositoryFixture = new BookingsRepositoryFixture(moduleRef);
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
schedulesService = moduleRef.get<SchedulesService_2024_04_15>(SchedulesService_2024_04_15);
organization = await teamRepositoryFixture.create({ name: "organization bookings" });
oAuthClient = await createOAuthClient(organization.id);
user = await userRepositoryFixture.create({
email: userEmail,
});
const userSchedule: CreateScheduleInput_2024_04_15 = {
name: "working time",
timeZone: "Europe/Rome",
isDefault: true,
};
await schedulesService.createUserSchedule(user.id, userSchedule);
const event = await eventTypesRepositoryFixture.create(
{ title: "peer coding", slug: eventTypeSlug, length: 60 },
user.id
);
eventTypeId = event.id;
app = moduleRef.createNestApplication();
bootstrap(app as NestExpressApplication);
await app.init();
});
async function createOAuthClient(organizationId: number) {
const data = {
logo: "logo-url",
name: "name",
redirectUris: ["http://localhost:5555"],
permissions: 32,
};
const secret = "secret";
const client = await oauthClientRepositoryFixture.create(organizationId, data, secret);
return client;
}
it("should be defined", () => {
expect(userRepositoryFixture).toBeDefined();
expect(user).toBeDefined();
});
it("should confirm a booking", async () => {
const status = "PENDING";
createdBooking1 = await bookingsRepositoryFixture.create({
user: {
connect: {
id: user.id,
},
},
startTime: new Date(Date.UTC(2050, 0, 7, 13, 0, 0)),
endTime: new Date(Date.UTC(2050, 0, 7, 14, 0, 0)),
title: "peer coding",
uid: "peer-coding-one",
eventType: {
connect: {
id: eventTypeId,
},
},
location: "via 10, rome, italy",
customInputs: {},
metadata: {},
responses: {
name: "Bob",
email: "bob@gmail.com",
},
attendees: {
create: {
email: "bob@gmail.com",
name: "Bob",
locale: "it",
timeZone: "Europe/Rome",
},
},
status,
});
expect(createdBooking1.status).toEqual("PENDING");
return request(app.getHttpServer())
.post(`/v2/bookings/${createdBooking1.uid}/confirm`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(200)
.then(async (response) => {
const responseBody: GetBookingOutput_2024_08_13 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
expect(responseDataIsBooking(responseBody.data)).toBe(true);
if (responseDataIsBooking(responseBody.data)) {
const data: BookingOutput_2024_08_13 = responseBody.data;
expect(data.uid).toBeDefined();
expect(data.status).toEqual("accepted");
const dbBooking = await bookingsRepositoryFixture.getByUid(data.uid);
expect(dbBooking?.status).toEqual("ACCEPTED");
} else {
throw new Error(
"Invalid response data - expected booking but received array of possibily recurring bookings"
);
}
});
});
it("should decline a booking", async () => {
const status = "PENDING";
createdBooking2 = await bookingsRepositoryFixture.create({
user: {
connect: {
id: user.id,
},
},
startTime: new Date(Date.UTC(2050, 0, 7, 10, 0, 0)),
endTime: new Date(Date.UTC(2050, 0, 7, 11, 0, 0)),
title: "peer coding",
uid: "peer-coding-two",
eventType: {
connect: {
id: eventTypeId,
},
},
location: "via 10, rome, italy",
customInputs: {},
metadata: {},
responses: {
name: "Bob",
email: "bob@gmail.com",
},
attendees: {
create: {
email: "bob@gmail.com",
name: "Bob",
locale: "it",
timeZone: "Europe/Rome",
},
},
status,
});
expect(createdBooking2.status).toEqual("PENDING");
return request(app.getHttpServer())
.post(`/v2/bookings/${createdBooking2.uid}/decline`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(200)
.then(async (response) => {
const responseBody: GetBookingOutput_2024_08_13 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
expect(responseDataIsBooking(responseBody.data)).toBe(true);
if (responseDataIsBooking(responseBody.data)) {
const data: BookingOutput_2024_08_13 = responseBody.data;
expect(data.uid).toBeDefined();
expect(data.status).toEqual("rejected");
const dbBooking = await bookingsRepositoryFixture.getByUid(data.uid);
expect(dbBooking?.status).toEqual("REJECTED");
} else {
throw new Error(
"Invalid response data - expected booking but received array of possibily recurring bookings"
);
}
});
});
afterAll(async () => {
await oauthClientRepositoryFixture.delete(oAuthClient.id);
await teamRepositoryFixture.delete(organization.id);
await userRepositoryFixture.deleteByEmail(user.email);
await bookingsRepositoryFixture.deleteAllBookings(user.id, user.email);
await app.close();
});
});
function responseDataIsBooking(data: any): data is BookingOutput_2024_08_13 {
return !Array.isArray(data) && typeof data === "object" && data && "id" in data;
}
});
@@ -0,0 +1,251 @@
import { bootstrap } from "@/app";
import { AppModule } from "@/app.module";
import { CancelBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/cancel-booking.output";
import { CreateBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/create-booking.output";
import { MarkAbsentBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/mark-absent.output";
import { RescheduleBookingOutput_2024_08_13 } from "@/ee/bookings/2024-08-13/outputs/reschedule-booking.output";
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { EventType, User } from "@prisma/client";
import * as request from "supertest";
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withApiAuth } from "test/utils/withApiAuth";
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
import { CreateBookingInput_2024_08_13, BookingOutput_2024_08_13 } from "@calcom/platform-types";
import { PlatformOAuthClient, Team } from "@calcom/prisma/client";
describe("Bookings Endpoints 2024-08-13", () => {
describe("User bookings", () => {
let app: INestApplication;
let organization: Team;
let userRepositoryFixture: UserRepositoryFixture;
let bookingsRepositoryFixture: BookingsRepositoryFixture;
let schedulesService: SchedulesService_2024_04_15;
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
let oAuthClient: PlatformOAuthClient;
let teamRepositoryFixture: TeamRepositoryFixture;
const userEmail = "bookings-controller-e2e@api.com";
let user: User;
let variableLengthEventType: EventType;
const variableLengthEventTypeSlug = "variable-length-event";
let normalEventType: EventType;
beforeAll(async () => {
const moduleRef = await withApiAuth(
userEmail,
Test.createTestingModule({
imports: [AppModule, PrismaModule, UsersModule, SchedulesModule_2024_04_15],
})
)
.overrideGuard(PermissionsGuard)
.useValue({
canActivate: () => true,
})
.compile();
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
bookingsRepositoryFixture = new BookingsRepositoryFixture(moduleRef);
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
schedulesService = moduleRef.get<SchedulesService_2024_04_15>(SchedulesService_2024_04_15);
organization = await teamRepositoryFixture.create({ name: "organization bookings" });
oAuthClient = await createOAuthClient(organization.id);
user = await userRepositoryFixture.create({
email: userEmail,
});
const userSchedule: CreateScheduleInput_2024_04_15 = {
name: "working time",
timeZone: "Europe/Rome",
isDefault: true,
};
await schedulesService.createUserSchedule(user.id, userSchedule);
variableLengthEventType = await eventTypesRepositoryFixture.create(
{
title: "variable length event",
slug: variableLengthEventTypeSlug,
length: 15,
metadata: { multipleDuration: [15, 30, 60] },
},
user.id
);
normalEventType = await eventTypesRepositoryFixture.create(
{ title: "normal event", slug: "normal-event", length: 15 },
user.id
);
app = moduleRef.createNestApplication();
bootstrap(app as NestExpressApplication);
await app.init();
});
async function createOAuthClient(organizationId: number) {
const data = {
logo: "logo-url",
name: "name",
redirectUris: ["http://localhost:5555"],
permissions: 32,
};
const secret = "secret";
const client = await oauthClientRepositoryFixture.create(organizationId, data, secret);
return client;
}
it("should be defined", () => {
expect(userRepositoryFixture).toBeDefined();
expect(user).toBeDefined();
});
describe("create bookings", () => {
it("should not be able to specify length of booking for non variable length event type", async () => {
const lengthInMinutes = 30;
const body: CreateBookingInput_2024_08_13 = {
start: new Date(Date.UTC(2030, 0, 8, 10, 0, 0)).toISOString(),
eventTypeId: normalEventType.id,
lengthInMinutes,
attendee: {
name: "Mr Proper",
email: "mr_proper@gmail.com",
timeZone: "Europe/Rome",
language: "it",
},
location: "https://meet.google.com/abc-def-ghi",
bookingFieldsResponses: {
customField: "customValue",
},
};
return request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(400);
});
it("should create a booking with default length", async () => {
const body: CreateBookingInput_2024_08_13 = {
start: new Date(Date.UTC(2030, 0, 8, 10, 0, 0)).toISOString(),
eventTypeId: variableLengthEventType.id,
attendee: {
name: "Mr Proper",
email: "mr_proper@gmail.com",
timeZone: "Europe/Rome",
language: "it",
},
location: "https://meet.google.com/abc-def-ghi",
bookingFieldsResponses: {
customField: "customValue",
},
};
return request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(201)
.then(async (response) => {
const responseBody: CreateBookingOutput_2024_08_13 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
expect(responseDataIsBooking(responseBody.data)).toBe(true);
if (responseDataIsBooking(responseBody.data)) {
const data: BookingOutput_2024_08_13 = responseBody.data;
expect(data.id).toBeDefined();
expect(data.uid).toBeDefined();
expect(data.status).toEqual("accepted");
expect(data.start).toEqual(body.start);
expect(data.end).toEqual(
new Date(Date.UTC(2030, 0, 8, 10, variableLengthEventType.length, 0)).toISOString()
);
expect(data.duration).toEqual(variableLengthEventType.length);
} else {
throw new Error(
"Invalid response data - expected booking but received array of possibily recurring bookings"
);
}
});
});
it("should create a booking with specified length that is not default length", async () => {
const lengthInMinutes = 30;
const body: CreateBookingInput_2024_08_13 = {
lengthInMinutes,
start: new Date(Date.UTC(2030, 0, 8, 11, 0, 0)).toISOString(),
eventTypeId: variableLengthEventType.id,
attendee: {
name: "Mr Proper",
email: "mr_proper@gmail.com",
timeZone: "Europe/Rome",
language: "it",
},
location: "https://meet.google.com/abc-def-ghi",
bookingFieldsResponses: {
customField: "customValue",
},
};
return request(app.getHttpServer())
.post("/v2/bookings")
.send(body)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(201)
.then(async (response) => {
const responseBody: CreateBookingOutput_2024_08_13 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
expect(responseDataIsBooking(responseBody.data)).toBe(true);
if (responseDataIsBooking(responseBody.data)) {
const data: BookingOutput_2024_08_13 = responseBody.data;
expect(data.id).toBeDefined();
expect(data.uid).toBeDefined();
expect(data.status).toEqual("accepted");
expect(data.start).toEqual(body.start);
expect(data.end).toEqual(new Date(Date.UTC(2030, 0, 8, 11, lengthInMinutes, 0)).toISOString());
expect(data.duration).toEqual(lengthInMinutes);
} else {
throw new Error(
"Invalid response data - expected booking but received array of possibily recurring bookings"
);
}
});
});
});
afterAll(async () => {
await oauthClientRepositoryFixture.delete(oAuthClient.id);
await teamRepositoryFixture.delete(organization.id);
await userRepositoryFixture.deleteByEmail(user.email);
await bookingsRepositoryFixture.deleteAllBookings(user.id, user.email);
await app.close();
});
});
function responseDataIsBooking(data: any): data is BookingOutput_2024_08_13 {
return !Array.isArray(data) && typeof data === "object" && data && "id" in data;
}
});
@@ -20,6 +20,7 @@ import {
roundRobinReassignment,
roundRobinManualReassignment,
handleMarkNoShow,
confirmBookingHandler,
} from "@calcom/platform-libraries";
import {
CreateBookingInput_2024_08_13,
@@ -414,4 +415,45 @@ export class BookingsService_2024_08_13 {
return this.outputService.getOutputReassignedBooking(reassigned);
}
async confirmBooking(bookingUid: string, requestUser: UserWithProfile) {
const booking = await this.bookingsRepository.getByUid(bookingUid);
if (!booking) {
throw new NotFoundException(`Booking with uid=${bookingUid} was not found in the database`);
}
await confirmBookingHandler({
ctx: {
user: requestUser,
},
input: {
bookingId: booking.id,
confirmed: true,
recurringEventId: booking.recurringEventId,
},
});
return this.getBooking(bookingUid);
}
async declineBooking(bookingUid: string, requestUser: UserWithProfile, reason?: string) {
const booking = await this.bookingsRepository.getByUid(bookingUid);
if (!booking) {
throw new NotFoundException(`Booking with uid=${bookingUid} was not found in the database`);
}
await confirmBookingHandler({
ctx: {
user: requestUser,
},
input: {
bookingId: booking.id,
confirmed: false,
recurringEventId: booking.recurringEventId,
reason,
},
});
return this.getBooking(bookingUid);
}
}
@@ -19,6 +19,7 @@ import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
import { X_CAL_CLIENT_ID } from "@calcom/platform-constants";
import { EventTypeMetaDataSchema } from "@calcom/platform-libraries";
import {
CancelBookingInput,
CancelBookingInput_2024_08_13,
@@ -32,6 +33,7 @@ import {
RescheduleBookingInput_2024_08_13,
RescheduleSeatedBookingInput_2024_08_13,
} from "@calcom/platform-types";
import { EventType } from "@calcom/prisma/client";
type BookingRequest = NextApiRequest & { userId: number | undefined } & OAuthRequestParams;
@@ -123,10 +125,13 @@ export class InputBookingsService_2024_08_13 {
throw new NotFoundException(`Event type with id=${inputBooking.eventTypeId} not found`);
}
this.validateBookingLengthInMinutes(inputBooking, eventType);
const lengthInMinutes = inputBooking.lengthInMinutes ?? eventType.length;
const startTime = DateTime.fromISO(inputBooking.start, { zone: "utc" }).setZone(
inputBooking.attendee.timeZone
);
const endTime = startTime.plus({ minutes: eventType.length });
const endTime = startTime.plus({ minutes: lengthInMinutes });
return {
start: startTime.toISO(),
@@ -150,6 +155,25 @@ export class InputBookingsService_2024_08_13 {
};
}
validateBookingLengthInMinutes(inputBooking: CreateBookingInput_2024_08_13, eventType: EventType) {
const eventTypeMetadata = EventTypeMetaDataSchema.parse(eventType.metadata);
if (inputBooking.lengthInMinutes && !eventTypeMetadata?.multipleDuration) {
throw new BadRequestException(
"Can't specify 'lengthInMinutes' because event type does not have multiple possible lengths. Please, remove the 'lengthInMinutes' field from the request."
);
}
if (
inputBooking.lengthInMinutes &&
!eventTypeMetadata?.multipleDuration?.includes(inputBooking.lengthInMinutes)
) {
throw new BadRequestException(
`Provided 'lengthInMinutes' is not one of the possible lengths for the event type. The possible lengths are: ${eventTypeMetadata?.multipleDuration?.join(
", "
)}`
);
}
}
async createRecurringBookingRequest(
request: Request,
body: CreateRecurringBookingInput_2024_08_13
@@ -212,6 +212,7 @@ describe("Event types Endpoints", () => {
slug: "coding-class",
description: "Let's learn how to code like a pro.",
lengthInMinutes: 60,
lengthInMinutesOptions: [30, 60, 90],
locations: [
{
type: "integration",
@@ -300,6 +301,7 @@ describe("Event types Endpoints", () => {
expect(createdEventType.title).toEqual(body.title);
expect(createdEventType.description).toEqual(body.description);
expect(createdEventType.lengthInMinutes).toEqual(body.lengthInMinutes);
expect(createdEventType.lengthInMinutesOptions).toEqual(body.lengthInMinutesOptions);
expect(createdEventType.locations).toEqual(body.locations);
expect(createdEventType.ownerId).toEqual(user.id);
expect(createdEventType.scheduleId).toEqual(firstSchedule.id);
@@ -360,6 +362,7 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType?.title).toEqual(eventType.title);
expect(fetchedEventType?.description).toEqual(eventType.description);
expect(fetchedEventType?.lengthInMinutes).toEqual(eventType.lengthInMinutes);
expect(fetchedEventType?.lengthInMinutesOptions).toEqual(eventType.lengthInMinutesOptions);
expect(fetchedEventType?.locations).toEqual(eventType.locations);
expect(fetchedEventType?.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType?.ownerId).toEqual(user.id);
@@ -665,6 +668,7 @@ describe("Event types Endpoints", () => {
const body: UpdateEventTypeInput_2024_06_14 = {
title: newTitle,
scheduleId: secondSchedule.id,
lengthInMinutesOptions: [15, 30],
bookingFields: [
nameBookingField,
{
@@ -733,6 +737,7 @@ describe("Event types Endpoints", () => {
expect(updatedEventType.id).toEqual(eventType.id);
expect(updatedEventType.title).toEqual(newTitle);
expect(updatedEventType.lengthInMinutesOptions).toEqual(body.lengthInMinutesOptions);
expect(updatedEventType.description).toEqual(eventType.description);
expect(updatedEventType.lengthInMinutes).toEqual(eventType.lengthInMinutes);
expect(updatedEventType.locations).toEqual(eventType.locations);
@@ -772,6 +777,7 @@ describe("Event types Endpoints", () => {
eventType.title = newTitle;
eventType.scheduleId = secondSchedule.id;
eventType.lengthInMinutesOptions = updatedEventType.lengthInMinutesOptions;
eventType.bookingLimitsCount = updatedEventType.bookingLimitsCount;
eventType.onlyShowFirstAvailableSlot = updatedEventType.onlyShowFirstAvailableSlot;
eventType.bookingLimitsDuration = updatedEventType.bookingLimitsDuration;
@@ -819,6 +825,7 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType.title).toEqual(eventType.title);
expect(fetchedEventType.description).toEqual(eventType.description);
expect(fetchedEventType.lengthInMinutes).toEqual(eventType.lengthInMinutes);
expect(fetchedEventType.lengthInMinutesOptions).toEqual(eventType.lengthInMinutesOptions);
expect(fetchedEventType.locations).toEqual(eventType.locations);
expect(fetchedEventType.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType.ownerId).toEqual(user.id);
@@ -857,6 +864,7 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType?.title).toEqual(eventType.title);
expect(fetchedEventType?.description).toEqual(eventType.description);
expect(fetchedEventType?.lengthInMinutes).toEqual(eventType.lengthInMinutes);
expect(fetchedEventType?.lengthInMinutesOptions).toEqual(eventType.lengthInMinutesOptions);
expect(fetchedEventType?.locations).toEqual(eventType.locations);
expect(fetchedEventType?.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType?.ownerId).toEqual(user.id);
@@ -104,6 +104,7 @@ export class InputEventTypesService_2024_06_14 {
const {
lengthInMinutes,
lengthInMinutesOptions,
locations,
bookingFields,
bookingLimitsCount,
@@ -135,6 +136,7 @@ export class InputEventTypesService_2024_06_14 {
bookerLayouts: this.transformInputBookerLayouts(bookerLayouts),
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
multipleDuration: lengthInMinutesOptions,
},
requiresConfirmation: confirmationPolicyTransformed?.requiresConfirmation ?? undefined,
requiresConfirmationWillBlockSlot:
@@ -152,6 +154,7 @@ export class InputEventTypesService_2024_06_14 {
async transformInputUpdateEventType(inputEventType: UpdateEventTypeInput_2024_06_14, eventTypeId: number) {
const {
lengthInMinutes,
lengthInMinutesOptions,
locations,
bookingFields,
bookingLimitsCount,
@@ -191,6 +194,7 @@ export class InputEventTypesService_2024_06_14 {
bookerLayouts: this.transformInputBookerLayouts(bookerLayouts),
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
multipleDuration: lengthInMinutesOptions,
},
recurringEvent: recurrence ? this.transformInputRecurrignEvent(recurrence) : undefined,
requiresConfirmation: confirmationPolicyTransformed?.requiresConfirmation ?? undefined,
@@ -153,6 +153,7 @@ export class OutputEventTypesService_2024_06_14 {
id,
ownerId,
lengthInMinutes: length,
lengthInMinutesOptions: metadata.multipleDuration,
title,
slug,
description: description || "",
+2
View File
@@ -28,6 +28,8 @@ export type Environment = {
RATE_LIMIT_DEFAULT_LIMIT_ACCESS_TOKEN: number;
RATE_LIMIT_DEFAULT_LIMIT: number;
RATE_LIMIT_DEFAULT_BLOCK_DURATION_MS: number;
AXIOM_DATASET: string;
AXIOM_TOKEN: string;
};
export const getEnv = <K extends keyof Environment>(key: K, fallback?: Environment[K]): Environment[K] => {
+18 -4
View File
@@ -1,5 +1,7 @@
import { WinstonTransport as AxiomTransport } from "@axiomhq/winston";
import type { LoggerOptions } from "winston";
import { format, transports } from "winston";
import { format, transports as Transports } from "winston";
import type Transport from "winston-transport";
const formattedTimestamp = format.timestamp({
format: "YYYY-MM-DD HH:mm:ss.SSS",
@@ -36,13 +38,25 @@ export const logLevels = {
export const loggerConfig = (): LoggerOptions => {
const isProduction = process.env.NODE_ENV === "production";
const transports: Transport[] = [];
transports.push(new Transports.Console());
if (!!process.env.AXIOM_TOKEN && !!process.env.AXIOM_DATASET) {
transports.push(
new AxiomTransport({
token: process.env.AXIOM_TOKEN,
dataset: process.env.AXIOM_DATASET,
})
);
}
return {
levels: logLevels,
level: process.env.LOG_LEVEL ?? "info",
format: isProduction ? WINSTON_PROD_FORMAT : WINSTON_DEV_FORMAT,
transports: [new transports.Console()],
exceptionHandlers: [new transports.Console()],
rejectionHandlers: [new transports.Console()],
transports,
exceptionHandlers: transports,
rejectionHandlers: transports,
defaultMeta: {
service: "cal-platform-api",
},
+12 -4
View File
@@ -1,4 +1,5 @@
import type { AppConfig } from "@/config/type";
import { getEnv } from "@/env";
import { Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
@@ -107,13 +108,20 @@ async function generateSwagger(app: NestExpressApplication<Server>) {
const document = SwaggerModule.createDocument(app, config);
document.paths = groupAndSortPathsByFirstTag(document.paths);
const outputFile = "./swagger/documentation.json";
const swaggerOutputFile = "./swagger/documentation.json";
const docsOutputFile = "../../../docs/api-reference/v2/openapi.json";
const stringifiedContents = JSON.stringify(document, null, 2);
if (fs.existsSync(outputFile)) {
fs.unlinkSync(outputFile);
if (fs.existsSync(swaggerOutputFile)) {
fs.unlinkSync(swaggerOutputFile);
}
fs.writeFileSync(outputFile, JSON.stringify(document, null, 2), { encoding: "utf8" });
fs.writeFileSync(swaggerOutputFile, stringifiedContents, { encoding: "utf8" });
if (fs.existsSync(docsOutputFile) && getEnv("NODE_ENV") === "development") {
fs.unlinkSync(docsOutputFile);
fs.writeFileSync(docsOutputFile, stringifiedContents, { encoding: "utf8" });
}
if (!process.env.DOCS_URL) {
SwaggerModule.setup("docs", app, document, {
@@ -46,9 +46,9 @@ export class BillingProcessor {
return;
}
const stripeSubscription = await this.stripeService.stripe.subscriptions.retrieve(
billingSubscription.subscriptionId
);
const stripeSubscription = await this.stripeService
.getStripe()
.subscriptions.retrieve(billingSubscription.subscriptionId);
if (!stripeSubscription?.id) {
this.logger.error(`Failed to retrieve stripe subscription (${billingSubscription.subscriptionId})`, {
teamId,
@@ -69,7 +69,7 @@ export class BillingProcessor {
return;
}
await this.stripeService.stripe.subscriptionItems.createUsageRecord(meteredItem.id, {
await this.stripeService.getStripe().subscriptionItems.createUsageRecord(meteredItem.id, {
action: "increment",
quantity: 1,
timestamp: "now",
@@ -1,10 +1,11 @@
import { PlatformPlan } from "@/modules/billing/types";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { Injectable } from "@nestjs/common";
import { Injectable, Logger } from "@nestjs/common";
@Injectable()
export class BillingRepository {
private readonly logger = new Logger("BillingRepository");
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
getBillingForTeam = (teamId: number) =>
@@ -30,6 +31,35 @@ export class BillingRepository {
billingCycleEnd: billingEnd,
subscriptionId,
plan: plan.toString(),
overdue: false,
},
});
}
async updateBillingOverdue(subId: string, cusId: string, overdue: boolean) {
try {
return this.dbWrite.prisma.platformBilling.update({
where: {
subscriptionId: subId,
customerId: cusId,
},
data: {
overdue,
},
});
} catch (err) {
this.logger.error("Could not update billing overdue", {
subId,
cusId,
err,
});
}
}
async deleteBilling(id: number) {
return this.dbWrite.prisma.platformBilling.delete({
where: {
id,
},
});
}
@@ -0,0 +1,211 @@
import { bootstrap } from "@/app";
import { AppModule } from "@/app.module";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { StripeService } from "@/modules/stripe/stripe.service";
import { TokensModule } from "@/modules/tokens/tokens.module";
import { UsersModule } from "@/modules/users/users.module";
import { UserWithProfile } from "@/modules/users/users.repository";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import Stripe from "stripe";
import * as request from "supertest";
import { PlatformBillingRepositoryFixture } from "test/fixtures/repository/billing.repository.fixture";
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
import { OrganizationRepositoryFixture } from "test/fixtures/repository/organization.repository.fixture";
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withApiAuth } from "test/utils/withApiAuth";
import { Team, PlatformOAuthClient, PlatformBilling } from "@calcom/prisma/client";
describe("Platform Billing Controller (e2e)", () => {
let app: INestApplication;
const userEmail = "platform-billing-controller-e2e@api.com";
let user: UserWithProfile;
let billing: PlatformBilling;
let userRepositoryFixture: UserRepositoryFixture;
let organizationsRepositoryFixture: OrganizationRepositoryFixture;
let profileRepositoryFixture: ProfileRepositoryFixture;
let membershipsRepositoryFixture: MembershipRepositoryFixture;
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
let oAuthClient: PlatformOAuthClient;
let platformBillingRepositoryFixture: PlatformBillingRepositoryFixture;
let organization: Team;
beforeAll(async () => {
const moduleRef = await withApiAuth(
userEmail,
Test.createTestingModule({
imports: [AppModule, PrismaModule, UsersModule, TokensModule],
})
).compile();
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
organizationsRepositoryFixture = new OrganizationRepositoryFixture(moduleRef);
profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
platformBillingRepositoryFixture = new PlatformBillingRepositoryFixture(moduleRef);
organization = await organizationsRepositoryFixture.create({ name: "platform billing" });
user = await userRepositoryFixture.create({
email: userEmail,
username: userEmail,
});
await profileRepositoryFixture.create({
uid: `usr-${user.id}`,
username: userEmail,
organization: {
connect: {
id: organization.id,
},
},
user: {
connect: {
id: user.id,
},
},
});
await membershipsRepositoryFixture.create({
role: "OWNER",
team: { connect: { id: organization.id } },
user: { connect: { id: user.id } },
accepted: true,
});
billing = await platformBillingRepositoryFixture.create(organization.id);
app = moduleRef.createNestApplication();
bootstrap(app as NestExpressApplication);
await app.init();
});
afterAll(async () => {
userRepositoryFixture.deleteByEmail(user.email);
await app.close();
});
it("/billing/webhook (POST) should set billing free plan for org", () => {
jest.spyOn(StripeService.prototype, "getStripe").mockImplementation(
() =>
({
webhooks: {
constructEventAsync: async () => {
return {
type: "checkout.session.completed",
data: {
object: {
metadata: {
teamId: organization.id,
plan: "FREE",
},
mode: "subscription",
},
},
};
},
},
} as unknown as Stripe)
);
return request(app.getHttpServer())
.post("/v2/billing/webhook")
.expect(200)
.then(async (res) => {
const billing = await platformBillingRepositoryFixture.get(organization.id);
expect(billing?.plan).toEqual("FREE");
});
});
it("/billing/webhook (POST) failed payment should set billing free plan to overdue", () => {
jest.spyOn(StripeService.prototype, "getStripe").mockImplementation(
() =>
({
webhooks: {
constructEventAsync: async () => {
return {
type: "invoice.payment_failed",
data: {
object: {
customer: billing?.customerId,
subscription: billing?.subscriptionId,
},
},
};
},
},
} as unknown as Stripe)
);
return request(app.getHttpServer())
.post("/v2/billing/webhook")
.expect(200)
.then(async (res) => {
const billing = await platformBillingRepositoryFixture.get(organization.id);
expect(billing?.overdue).toEqual(true);
});
});
it("/billing/webhook (POST) success payment should set billing free plan to not overdue", () => {
jest.spyOn(StripeService.prototype, "getStripe").mockImplementation(
() =>
({
webhooks: {
constructEventAsync: async () => {
return {
type: "invoice.payment_succeeded",
data: {
object: {
customer: billing?.customerId,
subscription: billing?.subscriptionId,
},
},
};
},
},
} as unknown as Stripe)
);
return request(app.getHttpServer())
.post("/v2/billing/webhook")
.expect(200)
.then(async (res) => {
const billing = await platformBillingRepositoryFixture.get(organization.id);
expect(billing?.overdue).toEqual(false);
});
});
it("/billing/webhook (POST) should delete subscription", () => {
jest.spyOn(StripeService.prototype, "getStripe").mockImplementation(
() =>
({
webhooks: {
constructEventAsync: async () => {
return {
type: "customer.subscription.deleted",
data: {
object: {
metadata: {
teamId: organization.id,
plan: "FREE",
},
id: billing?.subscriptionId,
},
},
};
},
},
} as unknown as Stripe)
);
return request(app.getHttpServer())
.post("/v2/billing/webhook")
.expect(200)
.then(async (res) => {
const billing = await platformBillingRepositoryFixture.get(organization.id);
expect(billing).toBeNull();
});
});
});
@@ -102,13 +102,26 @@ export class BillingController {
@Req() request: Request,
@Headers("stripe-signature") stripeSignature: string
): Promise<ApiResponse> {
const event = await this.billingService.stripeService.stripe.webhooks.constructEventAsync(
request.body,
stripeSignature,
this.stripeWhSecret
);
const event = await this.billingService.stripeService
.getStripe()
.webhooks.constructEventAsync(request.body, stripeSignature, this.stripeWhSecret);
await this.billingService.createOrUpdateStripeSubscription(event);
switch (event.type) {
case "checkout.session.completed":
await this.billingService.handleStripeCheckoutEvents(event);
break;
case "customer.subscription.deleted":
await this.billingService.handleStripeSubscriptionDeleted(event);
break;
case "invoice.payment_failed":
await this.billingService.handleStripePaymentFailed(event);
break;
case "invoice.payment_succeeded":
await this.billingService.handleStripePaymentSuccess(event);
break;
default:
break;
}
return {
status: "success",
@@ -64,7 +64,7 @@ export class BillingService implements OnModuleDestroy {
}
async redirectToSubscribeCheckout(teamId: number, plan: PlatformPlan, customerId?: string) {
const { url } = await this.stripeService.stripe.checkout.sessions.create({
const { url } = await this.stripeService.getStripe().checkout.sessions.create({
customer: customerId,
line_items: [
{
@@ -101,7 +101,7 @@ export class BillingService implements OnModuleDestroy {
const teamWithBilling = await this.teamsRepository.findByIdIncludeBilling(teamId);
const customerId = teamWithBilling?.platformBilling?.customerId;
const { url } = await this.stripeService.stripe.checkout.sessions.create({
const { url } = await this.stripeService.getStripe().checkout.sessions.create({
customer: customerId,
success_url: `${this.webAppUrl}/settings/platform/`,
cancel_url: `${this.webAppUrl}/settings/platform/plans`,
@@ -131,41 +131,92 @@ export class BillingService implements OnModuleDestroy {
);
}
async createOrUpdateStripeSubscription(event: Stripe.Event) {
if (event.type === "checkout.session.completed") {
const subscription = event.data.object as Stripe.Checkout.Session;
if (!subscription.metadata?.teamId) {
return {
status: "success",
};
}
const teamId = Number.parseInt(subscription.metadata.teamId);
const plan = subscription.metadata.plan;
if (!plan || !teamId) {
this.logger.log("Webhook received but not pertaining to Platform, discarding.");
return {
status: "success",
};
}
if (subscription.mode === "subscription") {
await this.setSubscriptionForTeam(
async handleStripeSubscriptionDeleted(event: Stripe.Event) {
const subscription = event.data.object as Stripe.Subscription;
const teamId = subscription?.metadata?.teamId;
const plan = PlatformPlan[subscription?.metadata?.plan?.toUpperCase() as keyof typeof PlatformPlan];
if (teamId && plan) {
const currentBilling = await this.billingRepository.getBillingForTeam(Number.parseInt(teamId));
if (currentBilling?.subscriptionId === subscription.id) {
await this.billingRepository.deleteBilling(currentBilling.id);
this.logger.log(`Stripe Subscription deleted`, {
customerId: currentBilling.customerId,
subscriptionId: currentBilling.subscriptionId,
teamId,
subscription.subscription as string,
PlatformPlan[plan.toUpperCase() as keyof typeof PlatformPlan]
);
});
return;
}
if (subscription.mode === "setup") {
await this.updateStripeSubscriptionForTeam(teamId, plan as PlatformPlan);
}
return {
status: "success",
};
this.logger.log("No platform billing found.");
return;
}
this.logger.log("Webhook received but not pertaining to Platform, discarding.");
return;
}
getSubscriptionIdFromInvoice(invoice: Stripe.Invoice): string | null {
if (typeof invoice.subscription === "string") {
return invoice.subscription;
} else if (invoice.subscription && typeof invoice.subscription === "object") {
return invoice.subscription.id;
} else {
return null;
}
}
getCustomerIdFromInvoice(invoice: Stripe.Invoice): string | null {
if (typeof invoice.customer === "string") {
return invoice.customer;
} else if (invoice.customer && typeof invoice.customer === "object") {
return invoice.customer.id;
} else {
return null;
}
}
async handleStripePaymentSuccess(event: Stripe.Event) {
const invoice = event.data.object as Stripe.Invoice;
const subscriptionId = this.getSubscriptionIdFromInvoice(invoice);
const customerId = this.getCustomerIdFromInvoice(invoice);
if (subscriptionId && customerId) {
await this.billingRepository.updateBillingOverdue(subscriptionId, customerId, false);
}
}
async handleStripePaymentFailed(event: Stripe.Event) {
const invoice = event.data.object as Stripe.Invoice;
const subscriptionId = this.getSubscriptionIdFromInvoice(invoice);
const customerId = this.getCustomerIdFromInvoice(invoice);
if (subscriptionId && customerId) {
await this.billingRepository.updateBillingOverdue(subscriptionId, customerId, true);
}
}
async handleStripeCheckoutEvents(event: Stripe.Event) {
const checkoutSession = event.data.object as Stripe.Checkout.Session;
if (!checkoutSession.metadata?.teamId) {
return;
}
const teamId = Number.parseInt(checkoutSession.metadata.teamId);
const plan = checkoutSession.metadata.plan;
if (!plan || !teamId) {
this.logger.log("Webhook received but not pertaining to Platform, discarding.");
return;
}
if (checkoutSession.mode === "subscription") {
await this.setSubscriptionForTeam(
teamId,
checkoutSession.subscription as string,
PlatformPlan[plan.toUpperCase() as keyof typeof PlatformPlan]
);
}
if (checkoutSession.mode === "setup") {
await this.updateStripeSubscriptionForTeam(teamId, plan as PlatformPlan);
}
return;
}
async updateStripeSubscriptionForTeam(teamId: number, plan: PlatformPlan) {
@@ -175,9 +226,9 @@ export class BillingService implements OnModuleDestroy {
throw new NotFoundException("Team plan not found");
}
const existingUserSubscription = await this.stripeService.stripe.subscriptions.retrieve(
teamWithBilling?.platformBilling?.subscriptionId
);
const existingUserSubscription = await this.stripeService
.getStripe()
.subscriptions.retrieve(teamWithBilling?.platformBilling?.subscriptionId);
const currentLicensedItem = existingUserSubscription.items.data.find(
(item) => item.price?.recurring?.usage_type === "licensed"
);
@@ -193,21 +244,23 @@ export class BillingService implements OnModuleDestroy {
throw new NotFoundException("There is no overage item present in the subscription");
}
await this.stripeService.stripe.subscriptions.update(teamWithBilling?.platformBilling?.subscriptionId, {
items: [
{
id: currentLicensedItem.id,
price: this.billingConfigService.get(plan)?.base,
},
{
id: currentOverageItem.id,
price: this.billingConfigService.get(plan)?.overage,
clear_usage: false,
},
],
billing_cycle_anchor: "now",
proration_behavior: "create_prorations",
});
await this.stripeService
.getStripe()
.subscriptions.update(teamWithBilling?.platformBilling?.subscriptionId, {
items: [
{
id: currentLicensedItem.id,
price: this.billingConfigService.get(plan)?.base,
},
{
id: currentOverageItem.id,
price: this.billingConfigService.get(plan)?.overage,
clear_usage: false,
},
],
billing_cycle_anchor: "now",
proration_behavior: "create_prorations",
});
await this.setSubscriptionForTeam(
teamId,
+2 -1
View File
@@ -1,8 +1,9 @@
export enum PlatformPlan {
FREE = "FREE",
STARTER = "STARTER",
ESSENTIALS = "ESSENTIALS",
SCALE = "SCALE",
ENTERPRISE = "ENTERPRISE",
}
export type PlatformPlanType = "STARTER" | "ESSENTIALS" | "SCALE" | "ENTERPRISE";
export type PlatformPlanType = "FREE" | "STARTER" | "ESSENTIALS" | "SCALE" | "ENTERPRISE";
@@ -25,9 +25,9 @@ import {
import {
ApiTags as DocsTags,
ApiExcludeController as DocsExcludeController,
ApiExcludeEndpoint as DocsExcludeEndpoint,
ApiOperation as DocsOperation,
ApiOkResponse as DocsOkResponse,
ApiExcludeEndpoint as DocsExcludeEndpoint,
ApiBadRequestResponse as DocsBadRequestResponse,
ApiHeader as DocsHeader,
} from "@nestjs/swagger";
@@ -50,20 +50,7 @@ export class OAuthFlowController {
@Post("/authorize")
@HttpCode(HttpStatus.OK)
@UseGuards(NextAuthGuard)
@DocsOperation({
summary: "Authorize an OAuth client",
description:
"Redirects the user to the specified 'redirect_uri' with an authorization code in query parameter if the client is authorized successfully. The code is then exchanged for access and refresh tokens via the `/exchange` endpoint.",
})
@DocsOkResponse({
description:
"The user is redirected to the 'redirect_uri' with an authorization code in query parameter e.g. `redirectUri?code=secretcode.`",
})
@DocsBadRequestResponse({
description:
"Bad request if the OAuth client is not found, if the redirect URI is invalid, or if the user has already authorized the client.",
})
@DocsExcludeEndpoint(getEnv("NODE_ENV") === "production")
@DocsExcludeEndpoint()
async authorize(
@Param("clientId") clientId: string,
@Body() body: OAuthAuthorizeInput,
@@ -97,20 +84,7 @@ export class OAuthFlowController {
@Post("/exchange")
@HttpCode(HttpStatus.OK)
@DocsOperation({
summary: "Exchange authorization code for access tokens",
description:
"Exchanges the authorization code received from the `/authorize` endpoint for access and refresh tokens. The authorization code should be provided in the 'Authorization' header prefixed with 'Bearer '.",
})
@DocsOkResponse({
type: KeysResponseDto,
description: "Successfully exchanged authorization code for access and refresh tokens.",
})
@DocsBadRequestResponse({
description:
"Bad request if the authorization code is missing, invalid, or if the client ID and secret do not match.",
})
@DocsExcludeEndpoint(getEnv("NODE_ENV") === "production")
@DocsExcludeEndpoint()
async exchange(
@Headers("Authorization") authorization: string,
@Param("clientId") clientId: string,
@@ -31,6 +31,7 @@ import {
HttpStatus,
HttpCode,
UnprocessableEntityException,
Logger,
} from "@nestjs/common";
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
import { plainToClass } from "class-transformer";
@@ -46,6 +47,8 @@ import { SkipTakePagination } from "@calcom/platform-types";
@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard, IsTeamInOrg, PlatformPlanGuard, IsAdminAPIEnabledGuard)
@DocsTags("Orgs / Teams / Memberships")
export class OrganizationsTeamsMembershipsController {
private logger = new Logger("OrganizationsTeamsMembershipsController");
constructor(
private organizationsTeamsMembershipsService: OrganizationsTeamsMembershipsService,
private oganizationsEventTypesService: OrganizationsEventTypesService,
@@ -148,7 +151,11 @@ export class OrganizationsTeamsMembershipsController {
);
if (!currentMembership.accepted && updatedMembership.accepted) {
await updateNewTeamMemberEventTypes(updatedMembership.userId, teamId);
try {
await updateNewTeamMemberEventTypes(updatedMembership.userId, teamId);
} catch (err) {
this.logger.error("Could not update new team member eventTypes", err);
}
}
return {
@@ -175,7 +182,11 @@ export class OrganizationsTeamsMembershipsController {
const membership = await this.organizationsTeamsMembershipsService.createOrgTeamMembership(teamId, data);
if (membership.accepted) {
await updateNewTeamMemberEventTypes(user.id, teamId);
try {
await updateNewTeamMemberEventTypes(user.id, teamId);
} catch (err) {
this.logger.error("Could not update new team member eventTypes", err);
}
}
return {
status: SUCCESS_STATUS,
@@ -33,7 +33,7 @@ export class OrganizationsRepository {
}
async createNewBillingRelation(orgId: number, plan?: PlatformPlan) {
const { id } = await this.stripeService.stripe.customers.create({
const { id } = await this.stripeService.getStripe().customers.create({
metadata: {
createdBy: "oauth_client_no_csid", // mark in case this is needed in the future.
},
@@ -28,7 +28,7 @@ type IntegrationOAuthCallbackState = {
@Injectable()
export class StripeService {
public stripe: Stripe;
private stripe: Stripe;
private redirectUri = `${this.config.get("api.url")}/stripe/save`;
constructor(
@@ -44,6 +44,10 @@ export class StripeService {
});
}
getStripe() {
return this.stripe;
}
async getStripeRedirectUrl(state: string, userEmail?: string, userName?: string | null) {
const { client_id } = await this.getStripeAppKeys();
@@ -82,7 +82,10 @@ export class WebhooksController {
}
@Get("/")
@ApiOperation({ summary: "Get all webooks (paginated)" })
@ApiOperation({
summary: "Get all webooks",
description: "Gets a paginated list of webhooks for the authenticated user.",
})
async getWebhooks(
@GetUser() user: UserWithProfile,
@Query() query: SkipTakePagination
+431 -116
View File
@@ -3257,6 +3257,230 @@
]
}
},
"/v2/bookings/{bookingUid}/reassign": {
"post": {
"operationId": "BookingsController_2024_08_13_reassignBooking",
"summary": "Automatically reassign booking to a new host",
"parameters": [
{
"name": "cal-api-version",
"in": "header",
"description": "Must be set to `2024-08-13`",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "bookingUid",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "Authorization",
"in": "header",
"description": "value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReassignBookingOutput_2024_08_13"
}
}
}
}
},
"tags": [
"Bookings"
]
}
},
"/v2/bookings/{bookingUid}/reassign/{userId}": {
"post": {
"operationId": "BookingsController_2024_08_13_reassignBookingToUser",
"summary": "Reassign a booking to a specific user",
"parameters": [
{
"name": "cal-api-version",
"in": "header",
"description": "Must be set to `2024-08-13`",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "bookingUid",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "userId",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "Authorization",
"in": "header",
"description": "value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReassignToUserBookingInput_2024_08_13"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReassignBookingOutput_2024_08_13"
}
}
}
}
},
"tags": [
"Bookings"
]
}
},
"/v2/bookings/{bookingUid}/confirm": {
"post": {
"operationId": "BookingsController_2024_08_13_confirmBooking",
"summary": "Confirm booking that requires a confirmation",
"parameters": [
{
"name": "cal-api-version",
"in": "header",
"description": "Must be set to `2024-08-13`",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "bookingUid",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "Authorization",
"in": "header",
"description": "value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetBookingOutput_2024_08_13"
}
}
}
}
},
"tags": [
"Bookings"
]
}
},
"/v2/bookings/{bookingUid}/decline": {
"post": {
"operationId": "BookingsController_2024_08_13_declineBooking",
"summary": "Decline booking that requires a confirmation",
"parameters": [
{
"name": "cal-api-version",
"in": "header",
"description": "Must be set to `2024-08-13`",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "bookingUid",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "Authorization",
"in": "header",
"description": "value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeclineBookingInput_2024_08_13"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetBookingOutput_2024_08_13"
}
}
}
}
},
"tags": [
"Bookings"
]
}
},
"/v2/calendars/ics-feed/save": {
"post": {
"operationId": "CalendarsController_createIcsFeed",
@@ -4214,97 +4438,6 @@
]
}
},
"/v2/oauth/{clientId}/authorize": {
"post": {
"operationId": "OAuthFlowController_authorize",
"summary": "Authorize an OAuth client",
"description": "Redirects the user to the specified 'redirect_uri' with an authorization code in query parameter if the client is authorized successfully. The code is then exchanged for access and refresh tokens via the `/exchange` endpoint.",
"parameters": [
{
"name": "clientId",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OAuthAuthorizeInput"
}
}
}
},
"responses": {
"200": {
"description": "The user is redirected to the 'redirect_uri' with an authorization code in query parameter e.g. `redirectUri?code=secretcode.`"
},
"400": {
"description": "Bad request if the OAuth client is not found, if the redirect URI is invalid, or if the user has already authorized the client."
}
},
"tags": [
"OAuth"
]
}
},
"/v2/oauth/{clientId}/exchange": {
"post": {
"operationId": "OAuthFlowController_exchange",
"summary": "Exchange authorization code for access tokens",
"description": "Exchanges the authorization code received from the `/authorize` endpoint for access and refresh tokens. The authorization code should be provided in the 'Authorization' header prefixed with 'Bearer '.",
"parameters": [
{
"name": "Authorization",
"required": true,
"in": "header",
"schema": {
"type": "string"
}
},
{
"name": "clientId",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExchangeAuthorizationCodeInput"
}
}
}
},
"responses": {
"200": {
"description": "Successfully exchanged authorization code for access and refresh tokens.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/KeysResponseDto"
}
}
}
},
"400": {
"description": "Bad request if the authorization code is missing, invalid, or if the client ID and secret do not match."
}
},
"tags": [
"OAuth"
]
}
},
"/v2/oauth/{clientId}/refresh": {
"post": {
"operationId": "OAuthFlowController_refreshAccessToken",
@@ -5033,6 +5166,37 @@
]
}
},
"/v2/stripe/check/{teamId}": {
"get": {
"operationId": "StripeController_checkTeamStripeConnection",
"summary": "Check team stripe connection",
"parameters": [
{
"name": "teamId",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StripCredentialsCheckOutputResponseDto"
}
}
}
}
},
"tags": [
"Stripe"
]
}
},
"/v2/timezones": {
"get": {
"operationId": "TimezonesController_getTimeZones",
@@ -5088,7 +5252,8 @@
},
"get": {
"operationId": "WebhooksController_getWebhooks",
"summary": "Get all webooks (paginated)",
"summary": "Get all webooks",
"description": "Gets a paginated list of webhooks for the authenticated user.",
"parameters": [
{
"name": "take",
@@ -5818,28 +5983,6 @@
}
}
},
"OAuthAuthorizeInput": {
"type": "object",
"properties": {
"redirectUri": {
"type": "string"
}
},
"required": [
"redirectUri"
]
},
"ExchangeAuthorizationCodeInput": {
"type": "object",
"properties": {
"clientSecret": {
"type": "string"
}
},
"required": [
"clientSecret"
]
},
"RefreshTokenInput": {
"type": "object",
"properties": {
@@ -6720,6 +6863,18 @@
"type": "number",
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -6943,6 +7098,7 @@
},
"required": [
"lengthInMinutes",
"lengthInMinutesOptions",
"title",
"slug"
]
@@ -8085,6 +8241,18 @@
"type": "number",
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -8308,6 +8476,7 @@
"required": [
"id",
"lengthInMinutes",
"lengthInMinutesOptions",
"title",
"slug",
"description",
@@ -8423,6 +8592,18 @@
"type": "number",
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -8643,7 +8824,10 @@
"hideCalendarEventDetails": {
"type": "boolean"
}
}
},
"required": [
"lengthInMinutesOptions"
]
},
"UpdateEventTypeOutput_2024_06_14": {
"type": "object",
@@ -9902,6 +10086,18 @@
"type": "number",
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -10138,6 +10334,7 @@
},
"required": [
"lengthInMinutes",
"lengthInMinutesOptions",
"title",
"slug",
"schedulingType",
@@ -10219,6 +10416,19 @@
"minimum": 1,
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "number",
"minimum": 1
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -10644,6 +10854,18 @@
"type": "number",
"example": 60
},
"lengthInMinutesOptions": {
"example": [
15,
30,
60
],
"description": "If you want that user can choose between different lengths of the event you can specify them here. Must include the provided `lengthInMinutes`.",
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string",
"example": "Learn the secrets of masterchief!"
@@ -10874,7 +11096,10 @@
"type": "boolean",
"description": "If true, all current and future team members will be assigned to this event type"
}
}
},
"required": [
"lengthInMinutesOptions"
]
},
"UpdateTeamEventTypeOutput": {
"type": "object",
@@ -12584,6 +12809,11 @@
"description": "The start time of the booking in ISO 8601 format in UTC timezone.",
"example": "2024-08-13T09:00:00Z"
},
"lengthInMinutes": {
"type": "number",
"example": 30,
"description": "If it is an event type that has multiple possible lengths that attendee can pick from, you can pass the desired booking length here.\n If not provided then event type default length will be used for the booking."
},
"eventTypeId": {
"type": "number",
"description": "The ID of the event type that is booked.",
@@ -12629,6 +12859,7 @@
},
"required": [
"start",
"lengthInMinutes",
"eventTypeId",
"attendee"
]
@@ -12641,6 +12872,11 @@
"description": "The start time of the booking in ISO 8601 format in UTC timezone.",
"example": "2024-08-13T09:00:00Z"
},
"lengthInMinutes": {
"type": "number",
"example": 30,
"description": "If it is an event type that has multiple possible lengths that attendee can pick from, you can pass the desired booking length here.\n If not provided then event type default length will be used for the booking."
},
"eventTypeId": {
"type": "number",
"description": "The ID of the event type that is booked.",
@@ -12691,6 +12927,7 @@
},
"required": [
"start",
"lengthInMinutes",
"eventTypeId",
"attendee",
"instant"
@@ -12704,6 +12941,11 @@
"description": "The start time of the booking in ISO 8601 format in UTC timezone.",
"example": "2024-08-13T09:00:00Z"
},
"lengthInMinutes": {
"type": "number",
"example": 30,
"description": "If it is an event type that has multiple possible lengths that attendee can pick from, you can pass the desired booking length here.\n If not provided then event type default length will be used for the booking."
},
"eventTypeId": {
"type": "number",
"description": "The ID of the event type that is booked.",
@@ -12754,6 +12996,7 @@
},
"required": [
"start",
"lengthInMinutes",
"eventTypeId",
"attendee"
]
@@ -13278,6 +13521,78 @@
"data"
]
},
"ReassignedToDto": {
"type": "object",
"properties": {
"id": {
"type": "number",
"example": 123
},
"name": {
"type": "string",
"example": "John Doe"
},
"email": {
"type": "string",
"example": "john.doe@example.com"
}
},
"required": [
"id",
"name",
"email"
]
},
"ReassignBookingOutput_2024_08_13": {
"type": "object",
"properties": {
"status": {
"type": "string",
"example": "success",
"enum": [
"success",
"error"
]
},
"data": {
"oneOf": [
{
"$ref": "#/components/schemas/ReassignBookingOutput_2024_08_13"
}
],
"description": "Booking data, which can be either a ReassignAutoBookingOutput object or a ReassignManualBookingOutput object",
"allOf": [
{
"$ref": "#/components/schemas/ReassignBookingOutput_2024_08_13"
}
]
}
},
"required": [
"status",
"data"
]
},
"ReassignToUserBookingInput_2024_08_13": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"example": "Host has to take another call",
"description": "Reason for reassigning the booking"
}
}
},
"DeclineBookingInput_2024_08_13": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"example": "Host has to take another call",
"description": "Reason for declining a booking that requires a confirmation"
}
}
},
"ReserveSlotInput": {
"type": "object",
"properties": {
@@ -23,6 +23,14 @@ export class PlatformBillingRepositoryFixture {
});
}
async get(orgId: number) {
return this.prismaWriteClient.platformBilling.findFirst({
where: {
id: orgId,
},
});
}
async deleteSubscriptionForTeam(teamId: number) {
// silently try to delete the subscription
try {
@@ -132,6 +132,7 @@ function BookingListItem(booking: BookingItemProps) {
});
const isUpcoming = new Date(booking.endTime) >= new Date();
const isOngoing = isUpcoming && new Date() >= new Date(booking.startTime);
const isBookingInPast = new Date(booking.endTime) < new Date();
const isCancelled = booking.status === BookingStatus.CANCELLED;
const isConfirmed = booking.status === BookingStatus.ACCEPTED;
@@ -269,7 +270,7 @@ function BookingListItem(booking: BookingItemProps) {
});
}
if (isBookingInPast) {
if (isBookingInPast || isOngoing) {
editBookingActions.push({
id: "no_show",
label: t("mark_as_no_show"),
@@ -8,12 +8,12 @@ type IndividualPlatformPlan = {
// if pricing or plans change in future modify this
export const platformPlans: IndividualPlatformPlan[] = [
{
plan: "Starter",
plan: "Free",
description:
"Perfect for just getting started with community support and access to hosted platform APIs, Cal.com Atoms (React components) and more.",
pricing: 99,
"The best plan to dip your toes into scheduling infrastructure. Start immediately with 25 free meetings per month",
pricing: 0,
includes: [
"Up to 100 bookings a month",
"Up to 25 bookings a month",
"$0.99 overage beyond",
"Community Support",
"Cal Atoms (React Library)",
@@ -37,7 +37,7 @@ export const PlatformBillingCard = ({
</h1>
<p className="pb-5 pt-3 text-base">{description}</p>
<h1 className="text-3xl font-semibold">
{pricing && (
{pricing !== undefined && (
<>
US${pricing} <span className="text-sm">per month</span>
</>
@@ -50,7 +50,7 @@ export const PlatformBillingCard = ({
loading={isLoading}
onClick={handleSubscribe}
className="flex w-[100%] items-center justify-center">
{pricing ? "Subscribe" : "Schedule a time"}
{pricing !== undefined ? "Subscribe" : "Schedule a time"}
</Button>
</div>
)}
+5 -4
View File
@@ -21,12 +21,13 @@ type HelpCardInfo = {
// if pricing or plans change in future modify this
export const platformPlans: IndividualPlatformPlan[] = [
{
plan: "Starter",
plan: "Free",
description:
"Perfect for just getting started with community support and access to hosted platform APIs, Cal.com Atoms (React components) and more.",
pricing: 99,
"The best plan to dip your toes into scheduling infrastructure. Start immediately with 25 free meetings per month",
pricing: 0,
includes: [
"Up to 100 bookings a month",
"Up to 25 bookings a month",
"$0.99 overage beyond",
"Community Support",
"Cal Atoms (React Library)",
"Platform APIs",
@@ -81,7 +81,7 @@ interface InfiniteEventTypeListProps {
group: InfiniteEventTypeGroup;
readOnly: boolean;
bookerUrl: string | null;
pages: { nextCursor: number | undefined; eventTypes: InfiniteEventType[] }[] | undefined;
pages: { nextCursor: number | null | undefined; eventTypes: InfiniteEventType[] }[] | undefined;
lockedByOrg?: boolean;
isPending?: boolean;
debouncedSearchTerm?: string;
@@ -349,9 +349,14 @@ export const InfiniteEventTypeList = ({
group: { teamId: group?.teamId, parentId: group?.parentId },
},
(data) => {
if (!data) return { pages: [], pageParams: [] };
return {
pageParams: data?.pageParams ?? [],
pages: newOrder,
...data,
pages: newOrder.map((page) => ({
...page,
nextCursor: page.nextCursor ?? undefined,
})),
};
}
);
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "4.6.21",
"version": "4.6.24",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
@@ -74,7 +74,7 @@
"@upstash/redis": "^1.21.0",
"@vercel/edge-config": "^0.1.1",
"@vercel/edge-functions-ui": "^0.2.1",
"@vercel/og": "^0.5.0",
"@vercel/og": "^0.6.3",
"accept-language-parser": "^1.5.0",
"async": "^3.2.4",
"bcp-47-match": "^2.0.3",
+3 -7
View File
@@ -83,7 +83,7 @@ export default async function handler(req: NextApiRequest) {
/>
),
ogConfig
) as { body: Buffer };
);
return new Response(img.body, {
status: 200,
@@ -97,9 +97,7 @@ export default async function handler(req: NextApiRequest) {
slug: searchParams.get("slug"),
imageType,
});
const img = new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig) as {
body: Buffer;
};
const img = new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig);
return new Response(img.body, { status: 200, headers: { "Content-Type": "image/png" } });
}
@@ -111,9 +109,7 @@ export default async function handler(req: NextApiRequest) {
imageType,
});
const img = new ImageResponse(<Generic title={title} description={description} />, ogConfig) as {
body: Buffer;
};
const img = new ImageResponse(<Generic title={title} description={description} />, ogConfig);
return new Response(img.body, { status: 200, headers: { "Content-Type": "image/png" } });
}
-3
View File
@@ -80,9 +80,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
},
});
// Sync Services: Close.com
// closeComUpdateTeam(prevTeam, team);
// redirect to team screen
res.redirect(302, `/settings/teams/${team.id}/onboard-members?event=team_created`);
}
+16 -3
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "الإجراء المطلوب إعادة الجدولة: يُرجى حجز وقت جديد لمدة {{eventType}} مع {{name}}",
"hi_user_name": "مرحبا {{name}}",
"ics_event_title": "{{eventType}} مع {{name}}",
"please_book_a_time_sometime_later": "عفواً، لم نتمكن من الاتصال بك هذه المرة. الرجاء جدولة مكالمة مستقبلية بدلاً من ذلك",
"please_book_a_time_sometime_later": "يبدو أن جميع خبرائنا مشغولون حاليًا. يرجى تحديد موعد مكالمة في الوقت الذي يناسبك وسنكون جاهزين لمساعدتك.",
"schedule_instead": "حدد موعدًا بدلاً من ذلك",
"new_event_subject": "حدث جديد: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "الانضمام بواسطة {{entryPoint}}",
"notes": "ملاحظات",
@@ -350,9 +351,13 @@
"other": "آخر",
"email_sign_in_subject": "رابط تسجيل الدخول بك لـ{{appName}}",
"round_robin_emailed_you_and_attendees": "أنت تجتمع مع {{user}}. أرسلنا بريداً إلكترونياً مع دعوة اجتماع بكل التفاصيل إلى الجميع.",
"round_robin_emailed_host_and_attendee": "{{host}} سيجتمع مع {{attendee}}. لقد أرسلنا بريداً إلكترونياً يحتوي على دعوة تقويم مع كافة التفاصيل للجميع.",
"emailed_you_and_attendees": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة للتقويم عبر البريد الإلكتروني تتضمن كل التفاصيل.",
"emailed_host_and_attendee": "لقد أرسلنا بريداً إلكترونياً يحتوي على دعوة تقويم مع كافة التفاصيل للجميع.",
"emailed_you_and_attendees_recurring": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة تقويم عبر البريد الإلكتروني لأول هذه الأحداث المتكررة.",
"round_robin_emailed_you_and_attendees_recurring": "أنت تجتمع مع {{user}}. أرسلنا بريداً إلكترونياً مع دعوة اجتماع بكل التفاصيل إلى الجميع لأول اجتماع من هذه الاجتماعات الدورية.",
"emailed_host_and_attendee_recurring": "لقد أرسلنا بريداً إلكترونياً يحتوي على دعوة تقويم مع كافة التفاصيل للجميع للحدث الأول من هذه الأحداث المتكررة.",
"round_robin_emailed_you_and_attendees_recurring": "أنت على موعد مع {{user}}. لقد أرسلنا بريداً إلكترونياً يحتوي على دعوة تقويم مع كافة التفاصيل للجميع للحدث الأول من هذه الأحداث المتكررة.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} سيجتمع مع {{attendee}}. لقد أرسلنا بريداً إلكترونياً يحتوي على دعوة تقويم مع كافة التفاصيل للجميع للحدث الأول من هذه الأحداث المتكررة.",
"emailed_you_and_any_other_attendees": "تم إرسال هذه المعلومات إليك وإلى الحضور الآخرين عبر البريد الإلكتروني.",
"needs_to_be_confirmed_or_rejected": "لا يزال الحجز الخاص بك يحتاج إلى التأكيد أو الرفض.",
"needs_to_be_confirmed_or_rejected_recurring": "لا يزال الاجتماع المتكرر الخاص بك بحاجة إلى التأكيد أو الرفض.",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "حدّد بعض الفترات المتاحة وأدرجها في رسالتك الإلكترونية",
"select_time": "اختيار الوقت",
"select_date": "اختيار التاريخ",
"connecting_you_to_someone": "نقوم بربطك بشخص ما.",
"connecting_you_to_someone": "نقوم بربطك بشخص من {{orgName}}.",
"please_do_not_close_this_tab": "من فضلك لا تغلق أو تحدّث هذه الصفحة",
"see_all_available_times": "رؤية كل الأوقات المتاحة",
"org_team_names_example_1": "مثال، فريق التسويق",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "معلومات وقت انتهاء الحدث في المنطقة الزمنية للحاضر",
"salesforce_create_event_on_contact": "إنشاء حدث على جهة الاتصال، إذا كانت موجودة. وإلا، الرجوع إلى العميل المحتمل",
"salesforce_owner_name_to_change": "اسم المالك المراد تغييره",
"dont_have_access_this_page": "ليس لديك صلاحية الوصول إلى هذه الصفحة",
"you_need_admin_or_owner_privileges_to_access": "لرؤية هذه الصفحة أو التفاعل معها، يجب أن تكون لديك صلاحيات المدير أو المالك",
"field_type": "نوع الحقل",
"when_to_write": "متى تتم الكتابة",
"salesforce_on_booking_write_to_record": "عند الحجز، اكتب في حقل مخصص في سجل الحاضر {{record}}",
@@ -2753,5 +2760,11 @@
"booking_start_date": "تاريخ بدء الحجز",
"booking_created_date": "تاريخ إنشاء الحجز",
"booking_reassigned_to_host": "تم إعادة تعيين الحجز إلى {{host}}",
"access_denied": "تم رفض الوصول",
"salesforce_route_to_owner": "سيكون مالك جهة الاتصال هو مضيف Round Robin إذا كان متاحاً",
"salesforce_do_not_route_to_owner": "لن يتم فرض مالك جهة الاتصال (يمكن أن يظل مضيفاً إذا تطابق مع السمات ومعايير Round Robin)",
"salesforce_route_to_custom_lookup_field": "التوجيه إلى مستخدم يطابق حقل البحث في الحساب",
"salesforce_option": "خيار Salesforce",
"lookup_field_name": "اسم حقل البحث",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ أضف السلاسل الجديدة أعلاه هنا ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+17 -4
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Təxirə salma tələb olunur: {{eventType}} {{name}} ilə yeni vaxt təyin edin",
"hi_user_name": "Salam {{name}}",
"ics_event_title": "{{eventType}} {{name}} ilə",
"please_book_a_time_sometime_later": "Bağışlayın, bu dəfə əlaqə qura bilmədik. Zəhmət olmasa, gələcək bir zəng üçün vaxt təyin edin",
"please_book_a_time_sometime_later": "Görünür ki, hazırda bütün ekspertlərimiz məşğuldur. Zəhmət olmasa, sizə ən uyğun olan vaxtı seçin və biz sizə kömək etməyə hazır olacağıq.",
"schedule_instead": "Əvəzində planlaşdırın",
"new_event_subject": "Yeni tədbir: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "{{entryPoint}} ilə qoşulun",
"notes": "Qeydlər",
@@ -350,9 +351,13 @@
"other": "Digər",
"email_sign_in_subject": "{{appName}} üçün giriş linkiniz",
"round_robin_emailed_you_and_attendees": "{{user}} ilə görüşürsünüz. Təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"round_robin_emailed_host_and_attendee": "{{host}} {{attendee}} ilə görüşür. Təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"emailed_you_and_attendees": "Təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"emailed_host_and_attendee": "Təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"emailed_you_and_attendees_recurring": "Bu təkrarlanan hadisələrin birincisi üçün təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"round_robin_emailed_you_and_attendees_recurring": "{{user}} ilə görüşürsünüz. Bu təkrarlanan hadisələrin birincisi üçün təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"emailed_host_and_attendee_recurring": "Bu təkrarlanan tədbirlərin birincisi üçün təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"round_robin_emailed_you_and_attendees_recurring": "Siz {{user}} ilə görüşürsünüz. Bu təkrarlanan tədbirlərin birincisi üçün təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} {{attendee}} ilə görüşür. Bu təkrarlanan tədbirlərin birincisi üçün təfərrüatları olan təqvim dəvəti ilə hər kəsə e-poçt göndərdik.",
"emailed_you_and_any_other_attendees": "Bu məlumatla hər kəsə e-poçt göndərdik.",
"needs_to_be_confirmed_or_rejected": "Rezervasiyanız hələ də təsdiqlənməli və ya rədd edilməlidir.",
"needs_to_be_confirmed_or_rejected_recurring": "Təkrarlanan görüşünüz hələ də təsdiqlənməli və ya rədd edilməlidir.",
@@ -1242,7 +1247,7 @@
"number_provided": "Telefon nömrəsi təmin ediləcək",
"before_event_trigger": "tədbir başlamazdan əvvəl",
"event_cancelled_trigger": "tədbir ləğv edildikdə",
"after_hosts_cal_video_no_show": "Ev sahibləri Cal video görüşünə qoşulmadıqdan sonra",
"after_hosts_cal_video_no_show": "Təşkilatçılar Cal video görüşünə qoşulmadıqdan sonra",
"after_guests_cal_video_no_show": "Qonaqlar Cal video görüşünə qoşulmadıqdan sonra",
"new_event_trigger": "yeni tədbir sifariş edildikdə",
"email_host_action": "ev sahibinə e-poçt göndərin",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Mövcud vaxtları seçin və Email-ə əlavə edin",
"select_time": "Vaxtı Seçin",
"select_date": "Tarixi Seçin",
"connecting_you_to_someone": "Sizi kiməsə qoşuruq.",
"connecting_you_to_someone": "Sizi {{orgName}}-dən birisi ilə əlaqələndiririk.",
"please_do_not_close_this_tab": "Zəhmət olmasa, bu səhifəni bağlamayın və ya yeniləməyin",
"see_all_available_times": "Bütün mövcud vaxtları görün",
"org_team_names_example_1": "məs. Marketinq Komandası",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "İştirakçı Saat Qurşağında Tədbirin Bitmə Vaxtı",
"salesforce_create_event_on_contact": "Əgər mövcuddursa, kontakt üzərində hadisə yaradın. Əks halda, lidə qayıdın",
"salesforce_owner_name_to_change": "Dəyişdiriləcək sahibin adı",
"dont_have_access_this_page": "Bu səhifəyə girişiniz yoxdur",
"you_need_admin_or_owner_privileges_to_access": "Bu səhifəni görmək və ya onunla qarşılıqlı əlaqədə olmaq üçün admin və ya sahib imtiyazlarına malik olmalısınız",
"field_type": "Sahə növü",
"when_to_write": "Nə zaman yazmaq",
"salesforce_on_booking_write_to_record": "Rezervasiya zamanı iştirakçının {{record}} qeydinə xüsusi sahəyə yaz",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Rezervasiyanın başlama tarixi",
"booking_created_date": "Rezervasiyanın yaradılma tarixi",
"booking_reassigned_to_host": "Rezervasiya {{host}}-a yenidən təyin edildi",
"access_denied": "Giriş qadağandır",
"salesforce_route_to_owner": "Əlaqə sahibi mövcud olduqda Round Robin ev sahibi olacaq",
"salesforce_do_not_route_to_owner": "Əlaqə sahibi məcbur edilməyəcək (əgər atributlara və Round Robin meyarlarına uyğun gəlirsə, yenə də ev sahibi ola bilər)",
"salesforce_route_to_custom_lookup_field": "Hesabda axtarış sahəsinə uyğun gələn istifadəçiyə yönləndir",
"salesforce_option": "Salesforce Seçimi",
"lookup_field_name": "Axtarış Sahəsinin Adı",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Yeni sətirləri bura əlavə edin ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Akce vyžadovaná k přeplánování: zarezervujte si nový čas pro událost {{eventType}} s osobou {{name}}",
"hi_user_name": "Hezký den, {{name}}",
"ics_event_title": "{{eventType}} s {{name}}",
"please_book_a_time_sometime_later": "Jejda, tentokrát jsme vás nemohli spojit. Prosím, naplánujte si hovor na později.",
"please_book_a_time_sometime_later": "Zdá se, že všichni naši experti jsou momentálně zaneprázdněni. Naplánujte si prosím hovor na čas, který vám nejvíce vyhovuje, a my vám rádi pomůžeme.",
"schedule_instead": "Naplánovat schůzku",
"new_event_subject": "Nová událost: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Připojit se k {{entryPoint}}",
"notes": "Poznámky",
@@ -350,9 +351,13 @@
"other": "Ostatní",
"email_sign_in_subject": "Váš přihlašovací odkaz pro {{appName}}",
"round_robin_emailed_you_and_attendees": "Setkáte se s {{user}}. Poslali jsme e-mail s pozvánkou do kalendáře a podrobnostmi všem účastníkům.",
"round_robin_emailed_host_and_attendee": "{{host}} se setká s {{attendee}}. Všem jsme poslali e-mail s pozvánkou do kalendáře a podrobnostmi.",
"emailed_you_and_attendees": "Poslali jsme vám a ostatním účastníkům e-mail s pozvánkou a podrobnostmi.",
"emailed_host_and_attendee": "Všem jsme poslali e-mail s pozvánkou do kalendáře a podrobnostmi.",
"emailed_you_and_attendees_recurring": "Na první z těchto opakovaných událostí jsme vám a ostatním účastníkům poslali e-mail s pozvánkou a podrobnostmi.",
"round_robin_emailed_you_and_attendees_recurring": "Setkáte se s {{user}}. Poslali jsme e-mail s pozvánkou do kalendáře a podrobnostmi všem účastníkům pro první z těchto opakujících se událostí.",
"emailed_host_and_attendee_recurring": "Všem jsme poslali e-mail s pozvánkou do kalendáře a podrobnostmi pro první z těchto opakujících se událostí.",
"round_robin_emailed_you_and_attendees_recurring": "Setkáte se s {{user}}. Všem jsme poslali e-mail s pozvánkou do kalendáře a podrobnostmi pro první z těchto opakujících se událostí.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} se setká s {{attendee}}. Všem jsme poslali e-mail s pozvánkou do kalendáře a podrobnostmi pro první z těchto opakujících se událostí.",
"emailed_you_and_any_other_attendees": "Poslali jsme vám a ostatním účastníkům e-mail s těmito informacemi.",
"needs_to_be_confirmed_or_rejected": "Vaše rezervace bude teprve schválena nebo zamítnuta.",
"needs_to_be_confirmed_or_rejected_recurring": "Vaše opakovaná schůzka musí být ještě potvrzena nebo zamítnuta.",
@@ -1242,8 +1247,8 @@
"number_provided": "Bude uvedeno telefonní číslo",
"before_event_trigger": "před zahájením události",
"event_cancelled_trigger": "při zrušení události",
"after_hosts_cal_video_no_show": "Po tom, co se hostitelé nepřipojí k cal video",
"after_guests_cal_video_no_show": "Po tom, co se hosté nepřipojí k cal video",
"after_hosts_cal_video_no_show": "Poté, co se hostitelé nepřipojili k video hovoru",
"after_guests_cal_video_no_show": "Poté, co se hosté nepřipojili k video hovoru",
"new_event_trigger": "při rezervaci nové události",
"email_host_action": "odeslání e-mailu hostiteli",
"email_attendee_action": "odeslat e-mail účastníkům",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Vyberte několik dostupných časů a vložte je do e-mailu",
"select_time": "Vyberte čas",
"select_date": "Vyberte datum",
"connecting_you_to_someone": "Spojujeme vás s někým.",
"connecting_you_to_someone": "Spojujeme vás s někým z {{orgName}}.",
"please_do_not_close_this_tab": "Prosím, nezavírejte ani neobnovujte tuto stránku",
"see_all_available_times": "Zobrazit všechny dostupné časy",
"org_team_names_example_1": "Např. marketingový tým",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Čas konce události v časovém pásmu účastníka",
"salesforce_create_event_on_contact": "Vytvořit událost na kontaktu, pokud existuje. Jinak použít lead",
"salesforce_owner_name_to_change": "Jméno vlastníka ke změně",
"dont_have_access_this_page": "K této stránce nemáte přístup",
"you_need_admin_or_owner_privileges_to_access": "Pro zobrazení nebo interakci s touto stránkou musíte mít administrátorská nebo vlastnická práva",
"field_type": "Typ pole",
"when_to_write": "Kdy zapisovat",
"salesforce_on_booking_write_to_record": "Při rezervaci zapsat do vlastního pole záznamu účastníka {{record}}",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Datum začátku rezervace",
"booking_created_date": "Datum vytvoření rezervace",
"booking_reassigned_to_host": "Rezervace přeřazena hostiteli {{host}}",
"access_denied": "Přístup odepřen",
"salesforce_route_to_owner": "Vlastník kontaktu bude hostem Round Robin, pokud je k dispozici",
"salesforce_do_not_route_to_owner": "Vlastník kontaktu nebude nucen (stále může být hostem, pokud odpovídá atributům a kritériím Round Robin)",
"salesforce_route_to_custom_lookup_field": "Přiřadit uživateli, který odpovídá vyhledávacímu poli na účtu",
"salesforce_option": "Možnost Salesforce",
"lookup_field_name": "Název vyhledávacího pole",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Přidejte své nové řetězce nahoru ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+17 -4
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Handling Påkrævet Omlægning: Reservér en ny tid for {{eventType}} med {{name}}",
"hi_user_name": "Hej {{name}}",
"ics_event_title": "{{eventType}} med {{name}}",
"please_book_a_time_sometime_later": "Ups, vi kunne ikke forbinde dig denne gang. Venligst planlæg et opkald på et senere tidspunkt.",
"please_book_a_time_sometime_later": "Det ser ud til, at alle vores eksperter er optaget lige nu. Venligst planlæg et opkald på et tidspunkt, der passer dig bedst, så vi er klar til at hjælpe dig.",
"schedule_instead": "Planlæg i stedet",
"new_event_subject": "Ny begivenhed: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Deltag via {{entryPoint}}",
"notes": "Noter",
@@ -350,9 +351,13 @@
"other": "Flere",
"email_sign_in_subject": "Dit login link til {{appName}}",
"round_robin_emailed_you_and_attendees": "Du mødes med {{user}}. Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle.",
"round_robin_emailed_host_and_attendee": "{{host}} mødes med {{attendee}}. Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle.",
"emailed_you_and_attendees": "Vi har sendt dig og de andre deltagere en kalenderinvitation med alle detaljerne.",
"emailed_host_and_attendee": "Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle.",
"emailed_you_and_attendees_recurring": "Vi har sendt dig og de andre deltagere en kalenderinvitation til den første af disse tilbagevendende begivenheder.",
"emailed_host_and_attendee_recurring": "Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle for den første af disse tilbagevendende begivenheder.",
"round_robin_emailed_you_and_attendees_recurring": "Du mødes med {{user}}. Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle for den første af disse tilbagevendende begivenheder.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} mødes med {{attendee}}. Vi har sendt en e-mail med en kalenderinvitation med detaljerne til alle for den første af disse tilbagevendende begivenheder.",
"emailed_you_and_any_other_attendees": "Du og eventuelle andre deltagere er blevet mailet med disse oplysninger.",
"needs_to_be_confirmed_or_rejected": "Din booking mangler stadig at blive bekræftet eller afvist.",
"needs_to_be_confirmed_or_rejected_recurring": "Dit tilbagevendende møde mangler stadig at blive bekræftet eller afvist.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefonnummer vil blive angivet",
"before_event_trigger": "før begivenheden starter",
"event_cancelled_trigger": "når begivenheden er aflyst",
"after_hosts_cal_video_no_show": "Efter værter ikke deltager i cal video",
"after_guests_cal_video_no_show": "Efter gæster ikke deltager i cal video",
"after_hosts_cal_video_no_show": "Efter værterne ikke deltog i cal-videomødet",
"after_guests_cal_video_no_show": "Efter gæsterne ikke deltog i cal-videomødet",
"new_event_trigger": "når ny begivenhed er booket",
"email_host_action": "send e-mail til vært",
"email_attendee_action": "send e-mail til deltagere",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Vælg nogle tilgængelige tidspunkter og indlejre dem i din e-mail",
"select_time": "Vælg tid",
"select_date": "Vælg dato",
"connecting_you_to_someone": "Vi forbinder dig med en person.",
"connecting_you_to_someone": "Vi forbinder dig med en person fra {{orgName}}.",
"please_do_not_close_this_tab": "Luk eller opdater venligst ikke denne side",
"see_all_available_times": "Se alle tilgængelige tidspunkter",
"org_team_names_example_1": "f.eks. Marketingteam",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Begivenhedens sluttidspunkt i deltagers tidszone",
"salesforce_create_event_on_contact": "Opret begivenhed på kontakt, hvis den eksisterer. Ellers fald tilbage til lead",
"salesforce_owner_name_to_change": "Ejernavn der skal ændres",
"dont_have_access_this_page": "Du har ikke adgang til denne side",
"you_need_admin_or_owner_privileges_to_access": "For at kunne se eller interagere med denne side, skal du have administrator- eller ejerrettigheder",
"field_type": "Felttype",
"when_to_write": "Hvornår der skal skrives",
"salesforce_on_booking_write_to_record": "Ved booking, skriv til et brugerdefineret felt på deltagerens {{record}}-post",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Bookings startdato",
"booking_created_date": "Dato for oprettelse af booking",
"booking_reassigned_to_host": "Booking omfordelt til {{host}}",
"access_denied": "Adgang nægtet",
"salesforce_route_to_owner": "Kontaktens ejer vil være Round Robin-vært, hvis tilgængelig",
"salesforce_do_not_route_to_owner": "Kontaktens ejer vil ikke blive tvunget (kan stadig være vært, hvis det matcher attributterne og Round Robin-kriterierne)",
"salesforce_route_to_custom_lookup_field": "Rute til en bruger, der matcher et opslagfelt på en konto",
"salesforce_option": "Salesforce-indstilling",
"lookup_field_name": "Opslagsfeltnavn",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Tilføj dine nye strenge ovenfor her ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Aktion erforderlich - Neuplanung: Bitte buchen Sie eine neue Zeit für „{{eventType}}“ mit {{name}}",
"hi_user_name": "Hallo, {{name}}",
"ics_event_title": "{{eventType}} mit {{name}}",
"please_book_a_time_sometime_later": "Ups, wir konnten Sie dieses Mal nicht verbinden. Bitte planen Sie stattdessen einen zukünftigen Anruf",
"please_book_a_time_sometime_later": "Es scheint, dass alle unsere Experten momentan beschäftigt sind. Bitte vereinbaren Sie einen Termin zu einem Zeitpunkt, der Ihnen am besten passt, und wir werden bereit sein, Ihnen zu helfen.",
"schedule_instead": "Stattdessen planen",
"new_event_subject": "Neuer Termin: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "{{entryPoint}} beitreten",
"notes": "Notizen",
@@ -350,9 +351,13 @@
"other": "Sonstige",
"email_sign_in_subject": "Ihr Anmelde-Link für {{appName}}",
"round_robin_emailed_you_and_attendees": "Sie treffen sich mit {{user}}. Wir haben eine E-Mail mit einer Kalendereinladung mit den Details an alle gesendet.",
"round_robin_emailed_host_and_attendee": "{{host}} trifft sich mit {{attendee}}. Wir haben allen eine E-Mail mit einer Kalendereinladung und den Details gesendet.",
"emailed_you_and_attendees": "Wir haben eine E-Mail mit einer Kalendereinladung mit den Details an alle gesendet.",
"emailed_host_and_attendee": "Wir haben allen eine E-Mail mit einer Kalendereinladung und den Details gesendet.",
"emailed_you_and_attendees_recurring": "Wir haben eine E-Mail mit einer Kalendereinladung mit den Details für das erste dieser wiederkehrenden Termine an alle gesendet.",
"round_robin_emailed_you_and_attendees_recurring": "Sie treffen sich mit {{user}}. Wir haben eine E-Mail mit einer Kalendereinladung mit den Details für das erste dieser wiederkehrenden Termine an alle gesendet.",
"emailed_host_and_attendee_recurring": "Wir haben allen eine E-Mail mit einer Kalendereinladung und den Details für das erste dieser wiederkehrenden Events gesendet.",
"round_robin_emailed_you_and_attendees_recurring": "Sie treffen sich mit {{user}}. Wir haben allen eine E-Mail mit einer Kalendereinladung und den Details für das erste dieser wiederkehrenden Events gesendet.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} trifft sich mit {{attendee}}. Wir haben allen eine E-Mail mit einer Kalendereinladung und den Details für das erste dieser wiederkehrenden Events gesendet.",
"emailed_you_and_any_other_attendees": "Wir haben eine E-Mail mit diesen Informationen an alle gesendet.",
"needs_to_be_confirmed_or_rejected": "Ihr Termin muss noch bestätigt oder abgelehnt werden.",
"needs_to_be_confirmed_or_rejected_recurring": "Ihr wiederkehrender Termin muss noch bestätigt oder abgelehnt werden.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefonnummer wird angegeben",
"before_event_trigger": "vor Beginn des Termins",
"event_cancelled_trigger": "wenn der Termin abgesagt wird",
"after_hosts_cal_video_no_show": "Nachdem Gastgeber nicht zum Cal-Video erscheinen",
"after_guests_cal_video_no_show": "Nachdem Gäste nicht zum Cal-Video erscheinen",
"after_hosts_cal_video_no_show": "Nachdem die Gastgeber nicht am Cal-Video teilgenommen haben",
"after_guests_cal_video_no_show": "Nachdem die Gäste nicht am Cal-Video teilgenommen haben",
"new_event_trigger": "wenn ein neuer Termin gebucht wird",
"email_host_action": "E-Mail an den Veranstalter senden",
"email_attendee_action": "E-Mail an Teilnehmende senden",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Zeiten zur E-Mail hinzufügen",
"select_time": "Zeit auswählen",
"select_date": "Datum auswählen",
"connecting_you_to_someone": "Wir verbinden Sie mit jemandem.",
"connecting_you_to_someone": "Wir verbinden Sie mit jemandem von {{orgName}}.",
"please_do_not_close_this_tab": "Bitte schließen oder aktualisieren Sie diese Seite nicht",
"see_all_available_times": "Alle verfügbaren Zeiten ansehen",
"org_team_names_example_1": "z.B. Marketing-Team",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Ereignis-Endzeit in der Zeitzone des Teilnehmers",
"salesforce_create_event_on_contact": "Event für Kontakt erstellen, falls vorhanden. Andernfalls auf Lead zurückgreifen",
"salesforce_owner_name_to_change": "Zu ändernder Besitzername",
"dont_have_access_this_page": "Sie haben keinen Zugriff auf diese Seite",
"you_need_admin_or_owner_privileges_to_access": "Um diese Seite anzuzeigen oder mit ihr zu interagieren, benötigen Sie Administrator- oder Eigentümerrechte",
"field_type": "Feldtyp",
"when_to_write": "Wann schreiben",
"salesforce_on_booking_write_to_record": "Bei Buchung in ein benutzerdefiniertes Feld des Teilnehmer-{{record}}-Datensatzes schreiben",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Buchungs-Startdatum",
"booking_created_date": "Buchungs-Erstellungsdatum",
"booking_reassigned_to_host": "Buchung an {{host}} neu zugewiesen",
"access_denied": "Zugriff verweigert",
"salesforce_route_to_owner": "Der Kontaktinhaber wird der Round Robin Host sein, falls verfügbar",
"salesforce_do_not_route_to_owner": "Der Kontaktinhaber wird nicht erzwungen (kann trotzdem Host sein, wenn die Attribute und Round Robin Kriterien übereinstimmen)",
"salesforce_route_to_custom_lookup_field": "Weiterleitung an einen Benutzer, der mit einem Lookup-Feld eines Accounts übereinstimmt",
"salesforce_option": "Salesforce-Option",
"lookup_field_name": "Name des Lookup-Felds",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Fügen Sie Ihre neuen Code-Zeilen über dieser hinzu ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Action Required Reschedule: Please book a new time for {{eventType}} with {{name}}",
"hi_user_name": "Hi {{name}}",
"ics_event_title": "{{eventType}} with {{name}}",
"please_book_a_time_sometime_later": "Oops, we couldn't connect you this time. Please schedule a future call instead",
"please_book_a_time_sometime_later": "It looks like all of our experts are busy right now. Please schedule a call at a time that works best for you and we'll be ready to assist you.",
"schedule_instead": "Schedule instead",
"new_event_subject": "New event: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Join by {{entryPoint}}",
"notes": "Notes",
@@ -1246,8 +1247,8 @@
"number_provided": "Phone number will be provided",
"before_event_trigger": "before event starts",
"event_cancelled_trigger": "when event is canceled",
"after_hosts_cal_video_no_show": "After hosts don't join cal video",
"after_guests_cal_video_no_show": "After guests don't join cal video",
"after_hosts_cal_video_no_show": "After hosts didn't join cal video",
"after_guests_cal_video_no_show": "After guests didn't join cal video",
"new_event_trigger": "when new event is booked",
"email_host_action": "send email to host",
"email_attendee_action": "send email to attendees",
@@ -2046,7 +2047,7 @@
"looking_for_more_analytics": "Looking for more analytics?",
"looking_for_more_insights": "Looking for more Insights?",
"filters": "Filters",
"add_filter": "Add filter",
"add_filter": "Add filter",
"add_rule": "Add rule",
"add_rule_group": "Add rule group",
"remove_filters": "Clear all filters",
@@ -2214,7 +2215,7 @@
"add_times_to_your_email": "Select a few available times and embed them in your Email",
"select_time": "Select Time",
"select_date": "Select Date",
"connecting_you_to_someone": "We are connecting you to someone.",
"connecting_you_to_someone": "We are connecting you to someone from {{orgName}}.",
"please_do_not_close_this_tab": "Please do not close or refresh this page",
"see_all_available_times": "See all available times",
"org_team_names_example_1": "e.g. Marketing Team",
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Acción requerida para reprogramar: Por favor, reserva un nuevo horario para {{eventType}} con {{name}}",
"hi_user_name": "Hola {{name}}",
"ics_event_title": "{{eventType}} con {{name}}",
"please_book_a_time_sometime_later": "Ups, no pudimos conectarte esta vez. Por favor, programa una llamada futura en su lugar",
"please_book_a_time_sometime_later": "Parece que todos nuestros expertos están ocupados en este momento. Por favor, agenda una llamada en el horario que más te convenga y estaremos listos para ayudarte.",
"schedule_instead": "Agendar ahora",
"new_event_subject": "Nuevo evento: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Únete por {{entryPoint}}",
"notes": "Notas",
@@ -350,9 +351,13 @@
"other": "Otro",
"email_sign_in_subject": "Tu enlace de inicio de sesión para {{appName}}",
"round_robin_emailed_you_and_attendees": "Te reunirás con {{user}}. Enviamos un correo electrónico con una invitación de calendario con los detalles a todos.",
"round_robin_emailed_host_and_attendee": "{{host}} se reunirá con {{attendee}}. Enviamos un correo electrónico con una invitación de calendario con los detalles a todos.",
"emailed_you_and_attendees": "Enviamos un correo electrónico con una invitación de calendario con los detalles a todos.",
"emailed_host_and_attendee": "Enviamos un correo electrónico con una invitación de calendario con los detalles a todos.",
"emailed_you_and_attendees_recurring": "Enviamos un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"emailed_host_and_attendee_recurring": "Enviamos un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Te reunirás con {{user}}. Enviamos un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} se reunirá con {{attendee}}. Enviamos un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"emailed_you_and_any_other_attendees": "Enviamos un correo electrónico a todos con esta información.",
"needs_to_be_confirmed_or_rejected": "Tu reserva aún necesita ser confirmada o rechazada.",
"needs_to_be_confirmed_or_rejected_recurring": "Tu reunión recurrente aún necesita ser confirmada o rechazada.",
@@ -1242,8 +1247,8 @@
"number_provided": "Se proporcionará el número de teléfono",
"before_event_trigger": "antes de que comience el evento",
"event_cancelled_trigger": "cuando el evento está cancelado",
"after_hosts_cal_video_no_show": "Después de que los anfitriones no se unan al video de Cal",
"after_guests_cal_video_no_show": "Después de que los invitados no se unan al video de Cal",
"after_hosts_cal_video_no_show": "Después de que los anfitriones no se unieron a la videollamada",
"after_guests_cal_video_no_show": "Después de que los invitados no se unieron a la videollamada",
"new_event_trigger": "cuando se reserva un nuevo evento",
"email_host_action": "enviar correo electrónico al anfitrión",
"email_attendee_action": "enviar correo electrónico a los asistentes",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Selecciona algunos horarios disponibles e insértalos en tu correo electrónico",
"select_time": "Seleccionar hora",
"select_date": "Seleccionar fecha",
"connecting_you_to_someone": "Te estamos conectando con alguien.",
"connecting_you_to_someone": "Te estamos conectando con alguien de {{orgName}}.",
"please_do_not_close_this_tab": "Por favor, no cierres ni actualices esta página",
"see_all_available_times": "Ver todos los horarios disponibles",
"org_team_names_example_1": "p. ej. Equipo de Marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Hora de finalización del evento en la zona horaria del asistente",
"salesforce_create_event_on_contact": "Crear evento en el contacto, si existe. De lo contrario, usar lead como alternativa",
"salesforce_owner_name_to_change": "Nombre del propietario a cambiar",
"dont_have_access_this_page": "No tienes acceso a esta página",
"you_need_admin_or_owner_privileges_to_access": "Para ver o interactuar con esta página, debes tener privilegios de administrador o propietario",
"field_type": "Tipo de campo",
"when_to_write": "Cuándo escribir",
"salesforce_on_booking_write_to_record": "Al reservar, escribir en un campo personalizado en el registro {{record}} del asistente",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Fecha de inicio de la reserva",
"booking_created_date": "Fecha de creación de la reserva",
"booking_reassigned_to_host": "Reserva reasignada a {{host}}",
"access_denied": "Acceso denegado",
"salesforce_route_to_owner": "El propietario del contacto será el anfitrión de Round Robin si está disponible",
"salesforce_do_not_route_to_owner": "El propietario del contacto no será forzado (aún puede ser anfitrión si coincide con los atributos y criterios de Round Robin)",
"salesforce_route_to_custom_lookup_field": "Dirigir a un usuario que coincida con un campo de búsqueda en una cuenta",
"salesforce_option": "Opción de Salesforce",
"lookup_field_name": "Nombre del campo de búsqueda",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Agrega tus nuevas cadenas arriba de esta línea ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+17 -4
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Reprogramar acción requerida: reserva una nueva hora para {{eventType}} con {{name}}",
"hi_user_name": "Hola {{name}}",
"ics_event_title": "{{eventType}} con {{name}}",
"please_book_a_time_sometime_later": "Vaya, no pudimos conectarte esta vez. Por favor, programa una llamada futura.",
"please_book_a_time_sometime_later": "Parece que todos nuestros expertos están ocupados en este momento. Por favor, programa una llamada en el horario que mejor te convenga y estaremos listos para ayudarte.",
"schedule_instead": "Programar ahora",
"new_event_subject": "Nuevo Evento: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Únase por {{entryPoint}}",
"notes": "Notas",
@@ -350,9 +351,13 @@
"other": "Otro",
"email_sign_in_subject": "Su enlace de inicio de sesión para {{appName}}",
"round_robin_emailed_you_and_attendees": "Te reunirás con {{user}}. Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos.",
"round_robin_emailed_host_and_attendee": "{{host}} se reunirá con {{attendee}}. Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos.",
"emailed_you_and_attendees": "Le enviamos a usted y a los demás asistentes una invitación al calendario con todos los detalles.",
"emailed_host_and_attendee": "Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos.",
"emailed_you_and_attendees_recurring": "Le enviamos a usted y a los demás asistentes una invitación al calendario para el primero de estos eventos recurrentes.",
"emailed_host_and_attendee_recurring": "Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Te reunirás con {{user}}. Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} se reunirá con {{attendee}}. Hemos enviado un correo electrónico con una invitación de calendario con los detalles a todos para el primero de estos eventos recurrentes.",
"emailed_you_and_any_other_attendees": "Usted y cualquier otro asistente han recibido esta información.",
"needs_to_be_confirmed_or_rejected": "Su reserva todavía necesita ser confirmada o rechazada.",
"needs_to_be_confirmed_or_rejected_recurring": "Su reunión recurrente todavía necesita confirmarse o rechazarse.",
@@ -1242,8 +1247,8 @@
"number_provided": "Se proporcionará el número de teléfono",
"before_event_trigger": "antes del inicio del evento",
"event_cancelled_trigger": "cuando se cancela el evento",
"after_hosts_cal_video_no_show": "Después de que los anfitriones no se unan al video de Cal",
"after_guests_cal_video_no_show": "Después de que los invitados no se unan al video de Cal",
"after_hosts_cal_video_no_show": "Después de que los anfitriones no se unieron al video de Cal",
"after_guests_cal_video_no_show": "Después de que los invitados no se unieron al video de Cal",
"new_event_trigger": "cuando se reserva un nuevo evento",
"email_host_action": "enviar correo electrónico al anfitrión",
"email_attendee_action": "enviar correo electrónico a los asistentes",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Seleccione algunos horarios disponibles e incrústelos en su correo electrónico",
"select_time": "Seleccione la hora",
"select_date": "Seleccione la fecha",
"connecting_you_to_someone": "Te estamos conectando con alguien.",
"connecting_you_to_someone": "Te estamos conectando con alguien de {{orgName}}.",
"please_do_not_close_this_tab": "Por favor, no cierres ni actualices esta página",
"see_all_available_times": "Ver todas las horas disponibles",
"org_team_names_example_1": "ej. Equipo de marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Hora de finalización del evento en la zona horaria del asistente",
"salesforce_create_event_on_contact": "Crear evento en el contacto, si existe. De lo contrario, usar el lead",
"salesforce_owner_name_to_change": "Nombre del propietario a cambiar",
"dont_have_access_this_page": "No tienes acceso a esta página",
"you_need_admin_or_owner_privileges_to_access": "Para ver o interactuar con esta página, debes tener privilegios de administrador o propietario",
"field_type": "Tipo de campo",
"when_to_write": "Cuándo escribir",
"salesforce_on_booking_write_to_record": "Al reservar, escribir en un campo personalizado en el registro {{record}} del asistente",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Fecha de inicio de la reserva",
"booking_created_date": "Fecha de creación de la reserva",
"booking_reassigned_to_host": "Reserva reasignada a {{host}}",
"access_denied": "Acceso denegado",
"salesforce_route_to_owner": "El propietario del contacto será el anfitrión de Round Robin si está disponible",
"salesforce_do_not_route_to_owner": "No se forzará al propietario del contacto (aún puede ser anfitrión si coincide con los atributos y criterios de Round Robin)",
"salesforce_route_to_custom_lookup_field": "Dirigir a un usuario que coincida con un campo de búsqueda en una cuenta",
"salesforce_option": "Opción de Salesforce",
"lookup_field_name": "Nombre del campo de búsqueda",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Agregue sus nuevas cadenas arriba ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Nõutud ümberajastamine: Palun broneerige oma {{eventType}} üritusele nimega {{name}} uus aeg",
"hi_user_name": "Tere, {{name}}",
"ics_event_title": "{{eventType}} koos {{name}}",
"please_book_a_time_sometime_later": "Vabandust, meil ei olnud võimalik teiega praegu ühendust luua. Ajastage selle asemel tulevane kõne",
"please_book_a_time_sometime_later": "Paistab, et kõik meie eksperdid on hetkel hõivatud. Palun broneeri kõne sulle sobivaks ajaks ja oleme valmis sind aitama.",
"schedule_instead": "Broneeri aeg",
"new_event_subject": "Uus üritus: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Liituge {{entryPoint}} viisil",
"notes": "Märkmed",
@@ -350,9 +351,13 @@
"other": "Muu",
"email_sign_in_subject": "Teie sisselogimislink rakendusele {{appName}}",
"round_robin_emailed_you_and_attendees": "Kohtute kasutajaga {{user}}. Saatsime kõigile meili kalendri kutsega koos üksikasjadega.",
"round_robin_emailed_host_and_attendee": "{{host}} kohtub {{attendee}}-ga. Saatsime kõigile e-kirja koos kalendrikutsega, mis sisaldab üksikasju.",
"emailed_you_and_attendees": "Saatsime kõigile kalendrikutse üksikasjadega meili.",
"emailed_host_and_attendee": "Saatsime kõigile e-kirja koos kalendrikutsega, mis sisaldab üksikasju.",
"emailed_you_and_attendees_recurring": "Saatsime kõigile esimeste korduvate sündmuste üksikasjadega meili kalendrikutsega.",
"round_robin_emailed_you_and_attendees_recurring": "Kohtute kasutajaga {{user}}. Saatsime kõigile kalendrikutse koos üksikasjadega meili esimese korduva sündmuse kohta.",
"emailed_host_and_attendee_recurring": "Saatsime kõigile e-kirja koos kalendrikutsega, mis sisaldab esimese korduva ürituse üksikasju.",
"round_robin_emailed_you_and_attendees_recurring": "Sa kohtud {{user}}-ga. Saatsime kõigile e-kirja koos kalendrikutsega, mis sisaldab esimese korduva ürituse üksikasju.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} kohtub {{attendee}}-ga. Saatsime kõigile e-kirja koos kalendrikutsega, mis sisaldab esimese korduva ürituse üksikasju.",
"emailed_you_and_any_other_attendees": "Saatsime selle teabega kõigile meili.",
"needs_to_be_confirmed_or_rejected": "Teie broneering tuleb veel kinnitada või tagasi lükata.",
"needs_to_be_confirmed_or_rejected_recurring": "Teie korduv koosolek tuleb veel kinnitada või tagasi lükata.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefoninumber antakse",
"before_event_trigger": "enne ürituse algust",
"event_cancelled_trigger": "Kui sündmus tühistatakse",
"after_hosts_cal_video_no_show": "Pärast seda, kui võõrustajad ei liitu Cal videokõnega",
"after_guests_cal_video_no_show": "Pärast seda, kui külalised ei liitu Cal videokõnega",
"after_hosts_cal_video_no_show": "Pärast seda, kui võõrustajad ei liitunud cal videoga",
"after_guests_cal_video_no_show": "Pärast seda, kui külalised ei liitunud cal videoga",
"new_event_trigger": "kui uus sündmus on broneeritud",
"email_host_action": "saada e-kiri hostile",
"email_attendee_action": "saada osalejatele e-kiri",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Valige mõned vabad ajad ja manustage need oma e-kirja",
"select_time": "Vali aeg",
"select_date": "Vali kuupäev",
"connecting_you_to_someone": "Me ühendame teid kellegagi.",
"connecting_you_to_someone": "Me ühendame teid kellegagi {{orgName}}-st.",
"please_do_not_close_this_tab": "Palun ärge sulgege ega värskendage seda lehte",
"see_all_available_times": "Vaata kõiki saadaolevaid aegu",
"org_team_names_example_1": "nt turundusmeeskond",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Sündmuse lõpuaeg osaleja ajavööndis",
"salesforce_create_event_on_contact": "Loo sündmus kontaktil, kui see eksisteerib. Vastasel juhul kasuta liidi",
"salesforce_owner_name_to_change": "Muudetava omaniku nimi",
"dont_have_access_this_page": "Teil ei ole sellele lehele juurdepääsu",
"you_need_admin_or_owner_privileges_to_access": "Selle lehe vaatamiseks või sellega suhtlemiseks peate omama administraatori või omaniku õigusi",
"field_type": "Välja tüüp",
"when_to_write": "Millal kirjutada",
"salesforce_on_booking_write_to_record": "Broneeringu korral kirjuta osaleja {{record}} kirje kohandatud väljale",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Broneeringu alguskuupäev",
"booking_created_date": "Broneeringu loomise kuupäev",
"booking_reassigned_to_host": "Broneering määrati ümber {{host}}-le",
"access_denied": "Juurdepääs keelatud",
"salesforce_route_to_owner": "Kontakti omanik on round robin host, kui saadaval",
"salesforce_do_not_route_to_owner": "Kontakti omanikku ei sunnita (võib siiski olla host, kui vastab atribuutidele ja round robin kriteeriumitele)",
"salesforce_route_to_custom_lookup_field": "Suuna kasutajale, kes vastab konto otsinguväljale",
"salesforce_option": "Salesforce'i valik",
"lookup_field_name": "Otsinguvälja nimi",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Replanification requise : veuillez réserver un nouveau créneau pour {{eventType}} avec {{name}}",
"hi_user_name": "Bonjour {{name}}",
"ics_event_title": "{{eventType}} avec {{name}}",
"please_book_a_time_sometime_later": "Oups, nous n'avons pas pu vous connecter cette fois-ci. Veuillez plutôt planifier un appel ultérieur",
"please_book_a_time_sometime_later": "Il semble que tous nos experts soient occupés pour le moment. Veuillez planifier un appel à un moment qui vous convient le mieux et nous serons prêts à vous aider.",
"schedule_instead": "Planifier à la place",
"new_event_subject": "Nouvel événement : {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Rejoindre par {{entryPoint}}",
"notes": "Notes",
@@ -350,9 +351,13 @@
"other": "Autre",
"email_sign_in_subject": "Votre lien de connexion pour {{appName}}",
"round_robin_emailed_you_and_attendees": "Vous avez rendez-vous avec {{user}}. Nous avons envoyé un e-mail avec une invitation de calendrier comprenant les détails à tout le monde.",
"round_robin_emailed_host_and_attendee": "{{host}} a un rendez-vous avec {{attendee}}. Nous avons envoyé un e-mail avec une invitation calendrier contenant tous les détails aux participants.",
"emailed_you_and_attendees": "Nous avons envoyé un e-mail avec une invitation de calendrier comprenant les détails à tout le monde.",
"emailed_host_and_attendee": "Nous avons envoyé un e-mail avec une invitation calendrier contenant tous les détails aux participants.",
"emailed_you_and_attendees_recurring": "Nous avons envoyé un e-mail avec une invitation de calendrier comprenant les détails à tout le monde pour le premier de ces événements récurrents.",
"round_robin_emailed_you_and_attendees_recurring": "Vous avez rendez-vous avec {{user}}. Nous avons envoyé un e-mail avec une invitation de calendrier comprenant les détails à tout le monde pour le premier de ces événements récurrents.",
"emailed_host_and_attendee_recurring": "Nous avons envoyé un e-mail avec une invitation calendrier contenant tous les détails aux participants pour le premier de ces événements récurrents.",
"round_robin_emailed_you_and_attendees_recurring": "Vous avez un rendez-vous avec {{user}}. Nous avons envoyé un e-mail avec une invitation calendrier contenant tous les détails aux participants pour le premier de ces événements récurrents.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} a un rendez-vous avec {{attendee}}. Nous avons envoyé un e-mail avec une invitation calendrier contenant tous les détails aux participants pour le premier de ces événements récurrents.",
"emailed_you_and_any_other_attendees": "Nous avons envoyé cette information à tout le monde par e-mail.",
"needs_to_be_confirmed_or_rejected": "Votre réservation doit encore être confirmée ou refusée.",
"needs_to_be_confirmed_or_rejected_recurring": "Votre rendez-vous récurrent doit encore être confirmé ou refusé.",
@@ -1242,8 +1247,8 @@
"number_provided": "Un numéro de téléphone sera fourni",
"before_event_trigger": "avant le début de l'événement",
"event_cancelled_trigger": "lorsque l'événement est annulé",
"after_hosts_cal_video_no_show": "Après que les hôtes ne rejoignent pas la vidéo Cal",
"after_guests_cal_video_no_show": "Après que les invités ne rejoignent pas la vidéo Cal",
"after_hosts_cal_video_no_show": "Après que les hôtes ne se sont pas connectés à l'appel vidéo",
"after_guests_cal_video_no_show": "Après que les invités ne se sont pas connectés à l'appel vidéo",
"new_event_trigger": "lorsqu'un nouvel événement est réservé",
"email_host_action": "envoyer un e-mail à l'hôte",
"email_attendee_action": "envoyer un e-mail aux participants",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Sélectionnez quelques créneaux disponibles et intégrez-les dans votre e-mail.",
"select_time": "Sélectionner un créneau",
"select_date": "Sélectionner une date",
"connecting_you_to_someone": "Nous vous mettons en relation avec quelqu'un.",
"connecting_you_to_someone": "Nous vous mettons en relation avec quelqu'un de {{orgName}}.",
"please_do_not_close_this_tab": "Veuillez ne pas fermer ou actualiser cette page",
"see_all_available_times": "Voir tous les créneaux disponibles",
"org_team_names_example_1": "p. ex. Équipe marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Heure de fin de l'événement dans le fuseau horaire du participant",
"salesforce_create_event_on_contact": "Créer un événement sur le contact, s'il existe. Sinon, utiliser le lead comme alternative",
"salesforce_owner_name_to_change": "Nom du propriétaire à modifier",
"dont_have_access_this_page": "Vous n'avez pas accès à cette page",
"you_need_admin_or_owner_privileges_to_access": "Pour voir ou interagir avec cette page, vous devez avoir des privilèges d'administrateur ou de propriétaire",
"field_type": "Type de champ",
"when_to_write": "Quand écrire",
"salesforce_on_booking_write_to_record": "Lors de la réservation, écrire dans un champ personnalisé sur l'enregistrement {{record}} du participant",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Date de début de la réservation",
"booking_created_date": "Date de création de la réservation",
"booking_reassigned_to_host": "Réservation réassignée à {{host}}",
"access_denied": "Accès refusé",
"salesforce_route_to_owner": "Le propriétaire du contact sera l'hôte Round Robin si disponible",
"salesforce_do_not_route_to_owner": "Le propriétaire du contact ne sera pas forcé (peut toujours être l'hôte si cela correspond aux attributs et aux critères Round Robin)",
"salesforce_route_to_custom_lookup_field": "Acheminer vers un utilisateur correspondant à un champ de recherche sur un compte",
"salesforce_option": "Option Salesforce",
"lookup_field_name": "Nom du champ de recherche",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "הפעולה חייבה קביעת מועד חדש: יש לקבוע מועד חדש עבור {{eventType}} עם {{name}}",
"hi_user_name": "שלום {{name}}",
"ics_event_title": "{{eventType}} עם {{name}}",
"please_book_a_time_sometime_later": "אף אחד לא זמין כרגע. נא לקבוע זימון למועד אחר",
"please_book_a_time_sometime_later": "נראה שכל המומחים שלנו עסוקים כרגע. אנא קבע/י שיחה בזמן שנוח לך ונשמח לסייע לך.",
"schedule_instead": "לקבוע במקום",
"new_event_subject": "אירוע חדש: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "ניתן להצטרף עד {{entryPoint}}",
"notes": "הערות",
@@ -350,9 +351,13 @@
"other": "אחר",
"email_sign_in_subject": "קישור הכניסה שלך אל {{appName}}",
"round_robin_emailed_you_and_attendees": "נקבעה לך פגישה עם {{user}}. שלחנו לך ולמשתתפים האחרים הודעת דוא״ל עם הזמנה בלוח השנה הכוללת את כל הפרטים.",
"round_robin_emailed_host_and_attendee": "{{host}} נפגש/ת עם {{attendee}}. שלחנו לכולם אימייל עם הזמנה ליומן הכוללת את כל הפרטים.",
"emailed_you_and_attendees": "שלחנו לך ולמשתתפים האחרים הודעת דוא\"ל עם הזמנה בלוח השנה הכוללת את כל הפרטים.",
"emailed_host_and_attendee": "שלחנו לכולם אימייל עם הזמנה ליומן הכוללת את כל הפרטים.",
"emailed_you_and_attendees_recurring": "שלחנו לך ולמשתתפים האחרים הודעת דוא\"ל עם הזמנה בלוח השנה לאירוע הראשון מבין האירועים החוזרים האלה.",
"round_robin_emailed_you_and_attendees_recurring": "נקבעה לך פגישה עם {{user}}. שלחנו לך ולמשתתפים האחרים הודעת דוא״ל עם הזמנה בלוח השנה לאירוע הראשון מבין האירועים החוזרים האלה.",
"emailed_host_and_attendee_recurring": "שלחנו לכולם אימייל עם הזמנה ליומן הכוללת את הפרטים עבור האירוע הראשון בסדרת האירועים החוזרים.",
"round_robin_emailed_you_and_attendees_recurring": "את/ה נפגש/ת עם {{user}}. שלחנו לכולם אימייל עם הזמנה ליומן הכוללת את הפרטים עבור האירוע הראשון בסדרת האירועים החוזרים.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} נפגש/ת עם {{attendee}}. שלחנו לכולם אימייל עם הזמנה ליומן הכוללת את הפרטים עבור האירוע הראשון בסדרת האירועים החוזרים.",
"emailed_you_and_any_other_attendees": "שלחנו לך ולמשתתפים האחרים, אם ישנם כאלה, הודעת דוא\"ל עם הפרטים האלה.",
"needs_to_be_confirmed_or_rejected": "ההזמנה שלך עדיין ממתינה לאישור או לדחייה.",
"needs_to_be_confirmed_or_rejected_recurring": "עדיין לא אישרת/דחית את הפגישה החוזרת.",
@@ -1242,8 +1247,8 @@
"number_provided": "מספר הטלפון יסופק",
"before_event_trigger": "לפני שהאירוע מתחיל",
"event_cancelled_trigger": "כאשר אירוע מבוטל",
"after_hosts_cal_video_no_show": "לאחר שהמארחים לא מצטרפים לשיחת הווידאו ב-Cal",
"after_guests_cal_video_no_show": "לאחר שהאורחים לא מצטרפים לשיחת הווידאו ב-Cal",
"after_hosts_cal_video_no_show": "לאחר שהמארחים לא הצטרפו לשיחת הוידאו",
"after_guests_cal_video_no_show": "לאחר שהאורחים לא הצטרפו לשיחת הוידאו",
"new_event_trigger": "כאשר אירוע חדש מוזמן",
"email_host_action": "שלח מייל למארח",
"email_attendee_action": "שליחת דוא\"ל למשתתפים",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "בחר/י כמה מועדים פנויים והטבע/י אותם בדוא\"ל",
"select_time": "בחירת שעה",
"select_date": "בחירת תאריך",
"connecting_you_to_someone": "אנו מחברים אותך למישהו או מישהי.",
"connecting_you_to_someone": "אנו מחברים אותך למישהו מ-{{orgName}}.",
"please_do_not_close_this_tab": "אנא אל תסגור או תרענן דף זה",
"see_all_available_times": "לצפייה בכל המועדים הפנויים",
"org_team_names_example_1": "לדוגמה, מחלקת שיווק",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "זמן סיום האירוע באזור הזמן של המשתתף",
"salesforce_create_event_on_contact": "צור אירוע על איש קשר, אם קיים. אחרת, חזור ללידים",
"salesforce_owner_name_to_change": "שם הבעלים לשינוי",
"dont_have_access_this_page": "אין לך גישה לדף זה",
"you_need_admin_or_owner_privileges_to_access": "כדי לצפות או לפעול בדף זה, עליך להיות בעל הרשאות מנהל או בעלים",
"field_type": "סוג שדה",
"when_to_write": "מתי לכתוב",
"salesforce_on_booking_write_to_record": "בעת הזמנה, כתוב לשדה מותאם אישית ברשומת המשתתף {{record}}",
@@ -2753,5 +2760,11 @@
"booking_start_date": "תאריך תחילת ההזמנה",
"booking_created_date": "תאריך יצירת ההזמנה",
"booking_reassigned_to_host": "ההזמנה הועברה למארח {{host}}",
"access_denied": "הגישה נדחתה",
"salesforce_route_to_owner": "בעל איש הקשר יהיה מארח ה-Round Robin אם זמין",
"salesforce_do_not_route_to_owner": "בעל איש הקשר לא יהיה מאולץ (עדיין יכול להיות מארח אם תואם את המאפיינים וקריטריוני ה-Round Robin)",
"salesforce_route_to_custom_lookup_field": "נתב למשתמש התואם לשדה חיפוש בחשבון",
"salesforce_option": "אפשרות Salesforce",
"lookup_field_name": "שם שדה החיפוש",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Átütmezés szükséges: Kérlek foglalj új időpontot a következőre: {{eventType}}, {{name}}",
"hi_user_name": "Szia {{name}}",
"ics_event_title": "{{eventType}} a következővel: {{name}}",
"please_book_a_time_sometime_later": "Hoppá, ezúttal nem tudtuk összekapcsolni. Kérjük, ütemezzen be egy jövőbeli hívást",
"please_book_a_time_sometime_later": "Úgy tűnik, hogy szakértőink jelenleg mind elfoglaltak. Kérjük, foglaljon időpontot egy önnek megfelelő időpontra, és készséggel állunk majd rendelkezésére.",
"schedule_instead": "Időpontfoglalás",
"new_event_subject": "Új esemény: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Csatlakozás a következővel: {{entryPoint}}",
"notes": "Jegyzetek",
@@ -350,9 +351,13 @@
"other": "Egyéb",
"email_sign_in_subject": "Bejelentkezési link a következőhöz: {{appName}}",
"round_robin_emailed_you_and_attendees": "Találkotó a következővel: {{user}}. Mindenkinek küldtünk egy naptári meghívót a részletekkel.",
"round_robin_emailed_host_and_attendee": "{{host}} találkozik {{attendee}} résztvevővel. Mindenkinek küldtünk egy e-mailt a naptári meghívóval és a részletekkel.",
"emailed_you_and_attendees": "Mindenkinek küldtünk egy e-mailt a naptár meghívóval és a részletekkel.",
"emailed_host_and_attendee": "Mindenkinek küldtünk egy e-mailt a naptári meghívóval és a részletekkel.",
"emailed_you_and_attendees_recurring": "Mindenkinek küldtünk e-mailben egy naptár meghívót a részletekkel az első ismétlődő eseményről.",
"round_robin_emailed_you_and_attendees_recurring": "Találkozó a következővel: {{user}}. E-mailben küldtünk egy naptári meghívót mindenkinek az első ismétlődő esemény részleteivel.",
"emailed_host_and_attendee_recurring": "Mindenkinek küldtünk egy e-mailt a naptári meghívóval és a részletekkel az ismétlődő események első alkalmára.",
"round_robin_emailed_you_and_attendees_recurring": "Ön találkozik {{user}} résztvevővel. Mindenkinek küldtünk egy e-mailt a naptári meghívóval és a részletekkel az ismétlődő események első alkalmára.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} találkozik {{attendee}} résztvevővel. Mindenkinek küldtünk egy e-mailt a naptári meghívóval és a részletekkel az ismétlődő események első alkalmára.",
"emailed_you_and_any_other_attendees": "Küldtünk egy e-mail-t mindenkinek ezekről az információkról.",
"needs_to_be_confirmed_or_rejected": "Foglalását még meg kell erősíteni vagy el kell utasítani.",
"needs_to_be_confirmed_or_rejected_recurring": "Az ismétlődő találkozót még meg kell erősíteni vagy el kell utasítani.",
@@ -1242,8 +1247,8 @@
"number_provided": "A telefonszámot megadjuk",
"before_event_trigger": "az esemény kezdete előtt",
"event_cancelled_trigger": "amikor az esemény le lett mondva",
"after_hosts_cal_video_no_show": "Miután a házigazdák nem csatlakoznak a cal videóhoz",
"after_guests_cal_video_no_show": "Miután a vendégek nem csatlakoznak a cal videóhoz",
"after_hosts_cal_video_no_show": "Miután a házigazdák nem csatlakoztak a Cal videóhoz",
"after_guests_cal_video_no_show": "Miután a vendégek nem csatlakoztak a Cal videóhoz",
"new_event_trigger": "új esemény lefoglalásakor",
"email_host_action": "küldjön e-mailt a házigazdának",
"email_attendee_action": "küldjön e-mailt a résztvevőknek",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Válasszon ki néhány elérhető időpontot, és ágyazza be e-mailjeibe",
"select_time": "Válasszon időt",
"select_date": "Válasszon dátumot",
"connecting_you_to_someone": "Összekapcsolunk valakivel.",
"connecting_you_to_someone": "Kapcsolatba hozzuk egy {{orgName}} munkatársával.",
"please_do_not_close_this_tab": "Kérjük, ne zárja be vagy frissítse ezt az oldalt",
"see_all_available_times": "Az összes elérhető időpont megtekintése",
"org_team_names_example_1": "például. Marketing Csapat",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Esemény befejezési ideje a résztvevő időzónájában",
"salesforce_create_event_on_contact": "Esemény létrehozása a kapcsolaton, ha létezik. Egyébként visszalépés a leadre",
"salesforce_owner_name_to_change": "Módosítandó tulajdonos neve",
"dont_have_access_this_page": "Nincs hozzáférése ehhez az oldalhoz",
"you_need_admin_or_owner_privileges_to_access": "Az oldal megtekintéséhez vagy használatához adminisztrátori vagy tulajdonosi jogosultság szükséges",
"field_type": "Mező típusa",
"when_to_write": "Mikor írjon",
"salesforce_on_booking_write_to_record": "Foglaláskor írjon egy egyéni mezőbe a résztvevő {{record}} rekordjában",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Foglalás kezdő dátuma",
"booking_created_date": "Foglalás létrehozásának dátuma",
"booking_reassigned_to_host": "Foglalás átirányítva a következő házigazdához: {{host}}",
"access_denied": "Hozzáférés megtagadva",
"salesforce_route_to_owner": "A kapcsolattartó tulajdonosa lesz a round robin házigazda, ha elérhető",
"salesforce_do_not_route_to_owner": "A kapcsolattartó tulajdonosa nem lesz kötelező (továbbra is lehet házigazda, ha megfelel a tulajdonságoknak és a round robin kritériumoknak)",
"salesforce_route_to_custom_lookup_field": "Átirányítás olyan felhasználóhoz, aki megfelel a fiók keresési mezőjének",
"salesforce_option": "Salesforce beállítás",
"lookup_field_name": "Keresési mező neve",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adja hozzá az új karakterláncokat fent ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Azione richiesta per la riprogrammazione: prenota un nuovo orario per {{eventType}} con {{name}}",
"hi_user_name": "Ciao {{name}}",
"ics_event_title": "{{eventType}} con {{name}}",
"please_book_a_time_sometime_later": "Oops, non siamo riusciti a collegarti. Pianifica una chiamata futura",
"please_book_a_time_sometime_later": "Sembra che tutti i nostri esperti siano occupati al momento. Ti invitiamo a programmare una chiamata in un momento che ti sia più comodo e saremo pronti ad assisterti.",
"schedule_instead": "Programma invece",
"new_event_subject": "Richiesta di nuovo evento: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Entra da {{entryPoint}}",
"notes": "Osservazioni",
@@ -350,9 +351,13 @@
"other": "Altro",
"email_sign_in_subject": "Link di accesso a {{appName}}",
"round_robin_emailed_you_and_attendees": "Avrai un incontro con {{user}}. Abbiamo inviato a tutti un'email di invito contenente tutte le informazioni.",
"round_robin_emailed_host_and_attendee": "{{host}} si incontra con {{attendee}}. Abbiamo inviato un'email con un invito al calendario con i dettagli a tutti.",
"emailed_you_and_attendees": "Abbiamo inviato via email a te e agli altri partecipanti un invito al calendario con tutti i dettagli.",
"emailed_host_and_attendee": "Abbiamo inviato un'email con un invito al calendario con i dettagli a tutti.",
"emailed_you_and_attendees_recurring": "Abbiamo inviato via email a te e agli altri partecipanti un invito al primo di questi eventi ricorrenti.",
"round_robin_emailed_you_and_attendees_recurring": "Avrai un incontro con {{user}}. Abbiamo inviato a tutti un'email di invito contenente tutte le informazioni per il primo di questi eventi ricorrenti.",
"emailed_host_and_attendee_recurring": "Abbiamo inviato un'email con un invito al calendario con i dettagli a tutti per il primo di questi eventi ricorrenti.",
"round_robin_emailed_you_and_attendees_recurring": "Ti incontri con {{user}}. Abbiamo inviato un'email con un invito al calendario con i dettagli a tutti per il primo di questi eventi ricorrenti.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} si incontra con {{attendee}}. Abbiamo inviato un'email con un invito al calendario con i dettagli a tutti per il primo di questi eventi ricorrenti.",
"emailed_you_and_any_other_attendees": "Tu e tutti gli altri partecipanti siete stati inviati via email con queste informazioni.",
"needs_to_be_confirmed_or_rejected": "La tua prenotazione deve ancora essere confermata o rifiutata.",
"needs_to_be_confirmed_or_rejected_recurring": "La tua riunione ricorrente deve ancora essere confermata o rifiutata.",
@@ -1242,8 +1247,8 @@
"number_provided": "Verrà fornito il numero di telefono",
"before_event_trigger": "prima dell'inizio dell'evento",
"event_cancelled_trigger": "quando l'evento viene cancellato",
"after_hosts_cal_video_no_show": "Dopo che gli host non si uniscono al video di Cal",
"after_guests_cal_video_no_show": "Dopo che gli ospiti non si uniscono al video di Cal",
"after_hosts_cal_video_no_show": "Dopo che gli host non si sono uniti alla videochiamata",
"after_guests_cal_video_no_show": "Dopo che gli ospiti non si sono uniti alla videochiamata",
"new_event_trigger": "quando viene prenotato un nuovo evento",
"email_host_action": "invia e-mail all'organizzatore",
"email_attendee_action": "invia e-mail ai partecipanti",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Seleziona alcuni orari disponibili e incorporali nella tua e-mail",
"select_time": "Seleziona l'ora",
"select_date": "Seleziona la data",
"connecting_you_to_someone": "Ti stiamo collegando con qualcuno.",
"connecting_you_to_someone": "Ti stiamo mettendo in contatto con qualcuno di {{orgName}}.",
"please_do_not_close_this_tab": "Per favore, non chiudere o aggiornare questa pagina",
"see_all_available_times": "Vedi tutti gli orari disponibili",
"org_team_names_example_1": "ad es., team di marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Ora di fine evento nel fuso orario del partecipante",
"salesforce_create_event_on_contact": "Crea evento sul contatto, se esiste. Altrimenti, passa al lead",
"salesforce_owner_name_to_change": "Nome del proprietario da modificare",
"dont_have_access_this_page": "Non hai accesso a questa pagina",
"you_need_admin_or_owner_privileges_to_access": "Per visualizzare o interagire con questa pagina, devi avere privilegi di amministratore o proprietario",
"field_type": "Tipo di campo",
"when_to_write": "Quando scrivere",
"salesforce_on_booking_write_to_record": "Al momento della prenotazione, scrivi in un campo personalizzato nel record {{record}} del partecipante",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Data di inizio prenotazione",
"booking_created_date": "Data di creazione della prenotazione",
"booking_reassigned_to_host": "Prenotazione riassegnata a {{host}}",
"access_denied": "Accesso negato",
"salesforce_route_to_owner": "Il proprietario del contatto sarà l'host del Round Robin se disponibile",
"salesforce_do_not_route_to_owner": "Il proprietario del contatto non sarà obbligato (può comunque essere l'host se corrisponde agli attributi e ai criteri del Round Robin)",
"salesforce_route_to_custom_lookup_field": "Instrada a un utente che corrisponde a un campo di ricerca su un account",
"salesforce_option": "Opzione Salesforce",
"lookup_field_name": "Nome del campo di ricerca",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Aggiungi le tue nuove stringhe qui sopra ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "スケジュール変更のアクションが必要です: {{name}} との {{eventType}} に新しい時間を予約してください",
"hi_user_name": "こんにちは、{{name}} さん",
"ics_event_title": "{{name}} との {{eventType}}",
"please_book_a_time_sometime_later": "おっと、今回は接続できませんでした。後で再度スケジュールしてください。",
"please_book_a_time_sometime_later": "現在、すべての専門家が対応中のようです。ご都合の良い時間にお電話を予約していただければ、準備してお待ちしております。",
"schedule_instead": "代わりに予約する",
"new_event_subject": "新規イベント: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "{{entryPoint}} に参加する",
"notes": "メモ",
@@ -350,9 +351,13 @@
"other": "その他",
"email_sign_in_subject": "{{appName}} のサインインリンク",
"round_robin_emailed_you_and_attendees": "{{user}}とのミーティングが設定されました。詳細を含むカレンダー招待を全員にメールで送信しました。",
"round_robin_emailed_host_and_attendee": "{{host}}が{{attendee}}と面談予定です。詳細を含む予定表の招待メールを全員に送信しました。",
"emailed_you_and_attendees": "あなたと他の出席者にすべての詳細を記載したカレンダーの招待状を電子メールで送信しました。",
"emailed_host_and_attendee": "詳細を含む予定表の招待メールを全員に送信しました。",
"emailed_you_and_attendees_recurring": "あなたと他の出席者にこの繰り返しイベント初回のカレンダーの招待状を電子メールで送信しました。",
"round_robin_emailed_you_and_attendees_recurring": "{{user}}との定期的なミーティングが設定されました。最初のイベントの詳細を含むカレンダー招待を全員にメールで送信しました。",
"emailed_host_and_attendee_recurring": "定期的な予定の最初の回について、詳細を含む予定表の招待メールを全員に送信しました。",
"round_robin_emailed_you_and_attendees_recurring": "あなたは{{user}}と面談予定です。定期的な予定の最初の回について、詳細を含む予定表の招待メールを全員に送信しました。",
"round_robin_emailed_host_and_attendee_recurring": "{{host}}が{{attendee}}と面談予定です。定期的な予定の最初の回について、詳細を含む予定表の招待メールを全員に送信しました。",
"emailed_you_and_any_other_attendees": "あなたと他の参加者にこの情報を電子メールで送信しました。",
"needs_to_be_confirmed_or_rejected": "予約は依然として確認または拒否が必要です。",
"needs_to_be_confirmed_or_rejected_recurring": "繰り返しミーティングは、まだ確認または拒否が必要です。",
@@ -1242,8 +1247,8 @@
"number_provided": "電話番号が提供されます",
"before_event_trigger": "イベント開始前に",
"event_cancelled_trigger": "イベントキャンセル時",
"after_hosts_cal_video_no_show": "ホストがCalビデオに参加しない場合",
"after_guests_cal_video_no_show": "ゲストがCalビデオに参加しない場合",
"after_hosts_cal_video_no_show": "ホストがCalビデオに参加しなかった後",
"after_guests_cal_video_no_show": "ゲストがCalビデオに参加しなかった後",
"new_event_trigger": "新しいイベント予約時に",
"email_host_action": "ホストにメールを送信",
"email_attendee_action": "出席者にメールを送る",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "出席できる時間帯をいくつか選んで、メールに埋め込みます",
"select_time": "時間帯を選ぶ",
"select_date": "日付を選ぶ",
"connecting_you_to_someone": "誰かに接続しています。",
"connecting_you_to_someone": "{{orgName}}の担当者におつなぎしています。",
"please_do_not_close_this_tab": "このページを閉じたり、リフレッシュしたりしないでください",
"see_all_available_times": "出席できる時間帯をすべて表示",
"org_team_names_example_1": "例:マーケティングチーム",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "参加者のタイムゾーンでのイベント終了時間",
"salesforce_create_event_on_contact": "連絡先が存在する場合はイベントを作成し、存在しない場合はリードにフォールバック",
"salesforce_owner_name_to_change": "変更する所有者名",
"dont_have_access_this_page": "このページにアクセスする権限がありません",
"you_need_admin_or_owner_privileges_to_access": "このページを表示または操作するには、管理者または所有者の権限が必要です",
"field_type": "フィールドタイプ",
"when_to_write": "書き込むタイミング",
"salesforce_on_booking_write_to_record": "予約時、参加者の{{record}}レコードのカスタムフィールドに書き込む",
@@ -2753,5 +2760,11 @@
"booking_start_date": "予約開始日",
"booking_created_date": "予約作成日",
"booking_reassigned_to_host": "予約が{{host}}に再割り当てされました",
"access_denied": "アクセスが拒否されました",
"salesforce_route_to_owner": "可能な場合、取引先責任者の所有者がラウンドロビンのホストになります",
"salesforce_do_not_route_to_owner": "取引先責任者の所有者は強制されません(属性とラウンドロビンの基準に一致する場合はホストになる可能性があります)",
"salesforce_route_to_custom_lookup_field": "取引先の参照項目に一致するユーザーに割り当てる",
"salesforce_option": "Salesforceオプション",
"lookup_field_name": "参照項目名",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ この上に新しい文字列を追加してください ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "ត្រូវតែកាលវិភាគឡើងវិញ: សូមកក់ពេលវេលាថ្មីសម្រាប់ {{eventType}} ជាមួយ {{name}}",
"hi_user_name": "សួស្តី {{name}}",
"ics_event_title": "{{eventType}} ជាមួយ {{name}}",
"please_book_a_time_sometime_later": "សូមទោស យើងមិនអាចភ្ជាប់អ្នកបាននៅពេលនេះទេ។ សូមកំណត់ពេលហៅម្តងទៀត។",
"please_book_a_time_sometime_later": "មើលទៅអ្នកជំនាញរបស់យើងទាំងអស់កំពុងជាប់រវល់នៅពេលនេះ។ សូមកំណត់ពេលវេលាហៅទូរស័ព្ទនៅពេលដែលងាយស្រួលសម្រាប់អ្នក ហើយយើងនឹងត្រៀមខ្លួនជាស្រេចដើម្បីជួយអ្នក។",
"schedule_instead": "កំណត់ពេលវេលាជំនួសវិញ",
"new_event_subject": "ព្រឹត្តិការណ៍ថ្មី៖ {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "ចូលរួមដោយ {{entryPoint}}",
"notes": "កំណត់ចំណាំ",
@@ -350,9 +351,13 @@
"other": "ផ្សេងទៀត",
"email_sign_in_subject": "តំណភ្ជាប់ចូលរបស់អ្នកសម្រាប់ {{appName}}",
"round_robin_emailed_you_and_attendees": "អ្នកកំពុងជួបជាមួយ {{user}}។ យើងបានផ្ញើអ៊ីមែលជាមួយការអញ្ជើញប្រតិទិនដែលមានព័ត៌មានលម្អិតទៅកាន់គ្រប់គ្នា។",
"round_robin_emailed_host_and_attendee": "{{host}} កំពុងជួបជាមួយ {{attendee}}។ យើងបានផ្ញើអ៊ីមែលដែលមានការអញ្ជើញកាលវិភាគជាមួយព័ត៌មានទៅអ្នកទាំងអស់គ្នា។",
"emailed_you_and_attendees": "យើងបានផ្ញើអ៊ីមែលជាមួយការអញ្ជើញប្រតិទិនដែលមានព័ត៌មានលម្អិតទៅកាន់គ្រប់គ្នា។",
"emailed_host_and_attendee": "យើងបានផ្ញើអ៊ីមែលដែលមានការអញ្ជើញកាលវិភាគជាមួយព័ត៌មានទៅអ្នកទាំងអស់គ្នា។",
"emailed_you_and_attendees_recurring": "យើងបានផ្ញើអ៊ីមែលជាមួយការអញ្ជើញប្រតិទិនដែលមានព័ត៌មានលម្អិតទៅកាន់គ្រប់គ្នាសម្រាប់ព្រឹត្តិការណ៍ដែលកើតឡើងជាថេរនេះ។",
"round_robin_emailed_you_and_attendees_recurring": "អ្នកកំពុងជួបជាមួយ {{user}}។ យើងបានផ្ញើអ៊ីមែលជាមួយការអញ្ជើញប្រតិទិនដែលមានព័ត៌មានលម្អិតទៅកាន់គ្រប់គ្នាសម្រាប់ព្រឹត្តិការណ៍ដែលកើតឡើងជាថេរនេះ។",
"emailed_host_and_attendee_recurring": "យើងបានផ្ញើអ៊ីមែលដែលមានការអញ្ជើញកាលវិភាគជាមួយព័ត៌មានទៅអ្នកទាំងអស់គ្នាសម្រាប់ព្រឹត្តិការណ៍ជាប្រចាំដំបូងនេះ។",
"round_robin_emailed_you_and_attendees_recurring": "អ្នកកំពុងជួបជាមួយ {{user}}។ យើងបានផ្ញើអ៊ីមែលដែលមានការអញ្ជើញកាលវិភាគជាមួយព័ត៌មានទៅអ្នកទាំងអស់គ្នាសម្រាប់ព្រឹត្តិការណ៍ជាប្រចាំដំបូងនេះ។",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} កំពុងជួបជាមួយ {{attendee}}។ យើងបានផ្ញើអ៊ីមែលដែលមានការអញ្ជើញកាលវិភាគជាមួយព័ត៌មានទៅអ្នកទាំងអស់គ្នាសម្រាប់ព្រឹត្តិការណ៍ជាប្រចាំដំបូងនេះ។",
"emailed_you_and_any_other_attendees": "យើងបានផ្ញើអ៊ីមែលទៅកាន់គ្រប់គ្នាជាមួយព័ត៌មាននេះ។",
"needs_to_be_confirmed_or_rejected": "ការកក់របស់អ្នកត្រូវការការបញ្ជាក់ឬបដិសេធ។",
"needs_to_be_confirmed_or_rejected_recurring": "ការជួបជុំជាថេររបស់អ្នកត្រូវការការបញ្ជាក់ឬបដិសេធ។",
@@ -1242,8 +1247,8 @@
"number_provided": "លេខទូរស័ព្ទនឹងត្រូវបានផ្តល់",
"before_event_trigger": "មុនព្រឹត្តិការណ៍ចាប់ផ្តើម",
"event_cancelled_trigger": "ពេលព្រឹត្តិការណ៍ត្រូវបានលុបចោល",
"after_hosts_cal_video_no_show": "បន្ទាប់ពីម្ចាស់ផ្ទះមិនចូលរួមវីដេអូ cal",
"after_guests_cal_video_no_show": "បន្ទាប់ពីភ្ញៀវមិនចូលរួមវីដេអូ cal",
"after_hosts_cal_video_no_show": "បន្ទាប់ពីម្ចាស់ផ្ទះមិនបានចូលរួមក្នុងវីដេអូ Cal",
"after_guests_cal_video_no_show": "បន្ទាប់ពីភ្ញៀវមិនបានចូលរួមក្នុងវីដេអូ Cal",
"new_event_trigger": "ពេលមានការកក់ព្រឹត្តិការណ៍ថ្មី",
"email_host_action": "ផ្ញើអ៊ីមែលទៅម្ចាស់",
"email_attendee_action": "ផ្ញើអ៊ីមែលទៅអ្នកចូលរួម",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "ជ្រើសរើសពេលវេលាដែលអាចប្រើបានប៉ុន្មាន និងបញ្ចូលវានៅក្នុងអ៊ីមែលរបស់អ្នក",
"select_time": "ជ្រើសរើសពេលវេលា",
"select_date": "ជ្រើសរើសកាលបរិច្ឆេទ",
"connecting_you_to_someone": "យើងកំពុងភ្ជាប់អ្នកទៅនរណាម្នាក់។",
"connecting_you_to_someone": "យើងកំពុងភ្ជាប់អ្នកទៅនរណាម្នាក់ពី {{orgName}}។",
"please_do_not_close_this_tab": "សូមកុំបិទ ឬធ្វើការបន្ទាន់សម័យទំព័រនេះ",
"see_all_available_times": "មើលពេលវេលាទាំងអស់ដែលអាចប្រើបាន",
"org_team_names_example_1": "ឧ. ក្រុមទីផ្សារ",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "ពេលវេលាបញ្ចប់ព្រឹត្តិការណ៍នៅក្នុងតំបន់ពេលវេលារបស់អ្នកចូលរួម",
"salesforce_create_event_on_contact": "បង្កើតព្រឹត្តិការណ៍នៅលើទំនាក់ទំនង បើមាន។ បើមិនដូច្នោះទេ ត្រឡប់ទៅ lead វិញ",
"salesforce_owner_name_to_change": "ឈ្មោះម្ចាស់ដែលត្រូវផ្លាស់ប្តូរ",
"dont_have_access_this_page": "អ្នកមិនមានសិទ្ធិចូលប្រើទំព័រនេះទេ",
"you_need_admin_or_owner_privileges_to_access": "ដើម្បីមើល ឬប្រើប្រាស់ទំព័រនេះ អ្នកត្រូវតែមានសិទ្ធិជាអ្នកគ្រប់គ្រង ឬម្ចាស់",
"field_type": "ប្រភេទវាល",
"when_to_write": "ពេលណាត្រូវសរសេរ",
"salesforce_on_booking_write_to_record": "នៅពេលកក់ សរសេរទៅវាលផ្ទាល់ខ្លួននៅលើកំណត់ត្រា {{record}} របស់អ្នកចូលរួម",
@@ -2753,5 +2760,11 @@
"booking_start_date": "កាលបរិច្ឆេទចាប់ផ្តើមការកក់",
"booking_created_date": "កាលបរិច្ឆេទបង្កើតការកក់",
"booking_reassigned_to_host": "ការកក់ត្រូវបានកំណត់ឡើងវិញទៅ {{host}}",
"access_denied": "ការចូលប្រើត្រូវបានបដិសេធ",
"salesforce_route_to_owner": "ម្ចាស់ទំនាក់ទំនងនឹងជាម្ចាស់ Round Robin ប្រសិនបើមានស្រាប់។",
"salesforce_do_not_route_to_owner": "ម្ចាស់ទំនាក់ទំនងនឹងមិនត្រូវបានបង្ខំ (អាចនៅតែជាម្ចាស់ប្រសិនបើវាដូចគ្នាជាមួយលក្ខណៈ និងលក្ខខណ្ឌ Round Robin)។",
"salesforce_route_to_custom_lookup_field": "ផ្លូវទៅកាន់អ្នកប្រើដែលត្រូវនឹងវាលស្វែងរកនៅលើគណនី។",
"salesforce_option": "ជម្រើស Salesforce",
"lookup_field_name": "ឈ្មោះវាលស្វែងរក",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ បន្ថែមខ្សែអក្សរថ្មីរបស់អ្នកនៅខាងលើនេះ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "일정 변경 조치 필요: {{name}} 님과 함께 새로운 {{eventType}} 시간을 예약하십시오",
"hi_user_name": "안녕하세요 {{name}}",
"ics_event_title": "{{eventType}}과 {{name}}",
"please_book_a_time_sometime_later": "죄송합니다, 이번에는 연결할 수 없었습니다. 나중에 다시 예약해 주세요.",
"please_book_a_time_sometime_later": "현재 모든 전문가가 바쁘신 것 같습니다. 귀하에게 가장 적합한 시간에 전화를 예약해 주시면 저희가 도와드리겠습니다.",
"schedule_instead": "대신 예약하기",
"new_event_subject": "새 이벤트: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "{{entryPoint}}로 가입하세요",
"notes": "노트",
@@ -350,9 +351,13 @@
"other": "더 보기",
"email_sign_in_subject": "{{appName}}의 로그인 링크",
"round_robin_emailed_you_and_attendees": "{{user}}와의 미팅이 예정되어 있습니다. 모든 참석자에게 캘린더 초대 이메일을 보냈습니다.",
"round_robin_emailed_host_and_attendee": "{{host}}님이 {{attendee}}님과 만납니다. 모든 사람에게 세부 사항이 포함된 캘린더 초대 이메일을 보냈습니다.",
"emailed_you_and_attendees": "당신과 다른 참여자들에게 상세 사항이 담긴 캘린더 초대 이메일을 보냈습니다.",
"emailed_host_and_attendee": "모든 사람에게 세부 사항이 포함된 캘린더 초대 이메일을 보냈습니다.",
"emailed_you_and_attendees_recurring": "귀하와 다른 참석자들에게 이 되풀이 이벤트의 첫 이벤트에 대한 예약 초대장을 이메일로 발송했습니다.",
"round_robin_emailed_you_and_attendees_recurring": "{{user}}와의 미팅이 예정되어 있습니다. 반복되는 이벤트의 첫 번째 일정에 대한 캘린더 초대 이메일을 모든 참석자에게 보냈습니다.",
"emailed_host_and_attendee_recurring": "반복되는 이벤트 중 첫 번째에 대한 세부 사항이 포함된 캘린더 초대 이메일을 모든 사람에게 보냈습니다.",
"round_robin_emailed_you_and_attendees_recurring": "{{user}}님과 만납니다. 반복되는 이벤트 중 첫 번째에 대한 세부 사항이 포함된 캘린더 초대 이메일을 모든 사람에게 보냈습니다.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}}님이 {{attendee}}님과 만납니다. 반복되는 이벤트 중 첫 번째에 대한 세부 사항이 포함된 캘린더 초대 이메일을 모든 사람에게 보냈습니다.",
"emailed_you_and_any_other_attendees": "당신과 다른 참여자들이 이 정보가 담긴 이메일을 주고 받았습니다.",
"needs_to_be_confirmed_or_rejected": "예약을 확정하거나 취소해주세요.",
"needs_to_be_confirmed_or_rejected_recurring": "되풀이 회의를 여전히 확인 또는 거부해야 합니다.",
@@ -1242,8 +1247,8 @@
"number_provided": "전화 번호는 제공됩니다",
"before_event_trigger": "이벤트 시작 전",
"event_cancelled_trigger": "이벤트 취소 시",
"after_hosts_cal_video_no_show": "호스트가 Cal 비디오에 참여하지 않은 후",
"after_guests_cal_video_no_show": "게스트가 Cal 비디오에 참여하지 않은 후",
"after_hosts_cal_video_no_show": "호스트가 Cal 비디오에 참여하지 않았습니다",
"after_guests_cal_video_no_show": "게스트가 Cal 비디오에 참여하지 않았습니다",
"new_event_trigger": "새 이벤트 예약 시",
"email_host_action": "호스트에게 이메일 발송",
"email_attendee_action": "참석자들에게 이메일 전송",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "사용 가능한 시간을 몇 개 선택하여 이메일에 포함시키세요",
"select_time": "시간 선택",
"select_date": "날짜 선택",
"connecting_you_to_someone": "다른 사람과 연결 중입니다.",
"connecting_you_to_someone": "{{orgName}}의 담당자와 연결 중입니다.",
"please_do_not_close_this_tab": "이 페이지를 닫거나 새로 고침하지 마세요",
"see_all_available_times": "모든 사용 가능한 시간 보기",
"org_team_names_example_1": "예: 마케팅 팀",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "참석자 시간대의 이벤트 종료 시간",
"salesforce_create_event_on_contact": "연락처가 존재하는 경우 이벤트 생성. 그렇지 않으면 리드로 대체",
"salesforce_owner_name_to_change": "변경할 소유자 이름",
"dont_have_access_this_page": "이 페이지에 접근할 수 없습니다",
"you_need_admin_or_owner_privileges_to_access": "이 페이지를 보거나 상호작용하려면 관리자 또는 소유자 권한이 필요합니다",
"field_type": "필드 유형",
"when_to_write": "작성 시기",
"salesforce_on_booking_write_to_record": "예약 시, 참석자 {{record}} 레코드의 사용자 정의 필드에 작성",
@@ -2753,5 +2760,11 @@
"booking_start_date": "예약 시작 날짜",
"booking_created_date": "예약 생성 날짜",
"booking_reassigned_to_host": "예약이 {{host}}에게 재할당됨",
"access_denied": "접근 거부됨",
"salesforce_route_to_owner": "연락처 소유자가 가능하면 Round Robin 호스트가 됩니다.",
"salesforce_do_not_route_to_owner": "연락처 소유자가 강제되지 않습니다 (속성과 Round Robin 기준이 일치하면 여전히 호스트가 될 수 있습니다).",
"salesforce_route_to_custom_lookup_field": "계정의 조회 필드와 일치하는 사용자에게 라우팅합니다.",
"salesforce_option": "Salesforce 옵션",
"lookup_field_name": "조회 필드 이름",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 여기에 새 문자열을 추가하세요 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+17 -4
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Actie vereist voor verplaatsing: boek een nieuwe tijd voor {{eventType}} met {{name}}",
"hi_user_name": "Hallo {{name}}",
"ics_event_title": "{{eventType}} met {{name}}",
"please_book_a_time_sometime_later": "Oeps, we konden je deze keer niet verbinden. Plan in plaats daarvan een toekomstige oproep.",
"please_book_a_time_sometime_later": "Het lijkt erop dat al onze experts momenteel bezet zijn. Plan een gesprek in op een moment dat jou het beste uitkomt en we staan klaar om je te helpen.",
"schedule_instead": "Plan in plaats daarvan",
"new_event_subject": "Nieuwe afspraak: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Word lid via {{entryPoint}}",
"notes": "Opmerkingen",
@@ -350,9 +351,13 @@
"other": "Overige",
"email_sign_in_subject": "Uw aanmeldingslink voor {{appName}}",
"round_robin_emailed_you_and_attendees": "Je hebt een afspraak met {{user}}. We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd.",
"round_robin_emailed_host_and_attendee": "{{host}} heeft een afspraak met {{attendee}}. We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd.",
"emailed_you_and_attendees": "We hebben u en de andere deelnemende een kalender uitnodiging met alle details gestuurd.",
"emailed_host_and_attendee": "We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd.",
"emailed_you_and_attendees_recurring": "We hebben u en de andere deelnemers een agenda-uitnodiging voor de eerste van deze terugkerende gebeurtenissen gestuurd.",
"emailed_host_and_attendee_recurring": "We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd voor de eerste van deze terugkerende evenementen.",
"round_robin_emailed_you_and_attendees_recurring": "Je hebt een afspraak met {{user}}. We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd voor de eerste van deze terugkerende evenementen.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} heeft een afspraak met {{attendee}}. We hebben een e-mail met een kalenderuitnodiging en de details naar iedereen gestuurd voor de eerste van deze terugkerende evenementen.",
"emailed_you_and_any_other_attendees": "U en alle andere deelnemers zijn gemaild met deze informatie.",
"needs_to_be_confirmed_or_rejected": "Uw boeking moet nog steeds worden bevestigd of geweigerd.",
"needs_to_be_confirmed_or_rejected_recurring": "Uw terugkerende afspraak moet nog steeds bevestigd of geweigerd worden.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefoonnummer wordt verstrekt",
"before_event_trigger": "voordat de gebeurtenis begint",
"event_cancelled_trigger": "wanneer de gebeurtenis is geannuleerd",
"after_hosts_cal_video_no_show": "Nadat hosts niet deelnemen aan cal video",
"after_guests_cal_video_no_show": "Nadat gasten niet deelnemen aan cal video",
"after_hosts_cal_video_no_show": "Nadat hosts niet bij de cal video zijn gekomen",
"after_guests_cal_video_no_show": "Nadat gasten niet bij de cal video zijn gekomen",
"new_event_trigger": "wanneer een nieuwe gebeurtenis is geboekt",
"email_host_action": "e-mail naar organisator versturen",
"email_attendee_action": "e-mail naar deelnemers versturen",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Selecteer enkele beschikbare tijden en voeg ze toe aan uw e-mail",
"select_time": "Tijd selecteren",
"select_date": "Datum selecteren",
"connecting_you_to_someone": "We verbinden je met iemand.",
"connecting_you_to_someone": "We verbinden je met iemand van {{orgName}}.",
"please_do_not_close_this_tab": "Sluit of vernieuw deze pagina niet",
"see_all_available_times": "Bekijk alle beschikbare tijden",
"org_team_names_example_1": "bijvoorbeeld Marketingteam",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Eindtijd evenement in tijdzone deelnemer",
"salesforce_create_event_on_contact": "Maak een evenement aan op het contact, indien aanwezig. Anders terugvallen op lead",
"salesforce_owner_name_to_change": "Eigenaarsnaam om te wijzigen",
"dont_have_access_this_page": "Je hebt geen toegang tot deze pagina",
"you_need_admin_or_owner_privileges_to_access": "Om deze pagina te bekijken of ermee te communiceren, moet je over admin- of eigenaarsrechten beschikken",
"field_type": "Veldtype",
"when_to_write": "Wanneer schrijven",
"salesforce_on_booking_write_to_record": "Bij boeking, schrijf naar een aangepast veld op het {{record}}-record van de deelnemer",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Startdatum boeking",
"booking_created_date": "Aanmaakdatum boeking",
"booking_reassigned_to_host": "Boeking opnieuw toegewezen aan {{host}}",
"access_denied": "Toegang geweigerd",
"salesforce_route_to_owner": "Contacteigenaar zal de Round Robin host zijn indien beschikbaar",
"salesforce_do_not_route_to_owner": "Contacteigenaar wordt niet geforceerd (kan nog steeds host zijn als het overeenkomt met de attributen en Round Robin criteria)",
"salesforce_route_to_custom_lookup_field": "Routeer naar een gebruiker die overeenkomt met een zoekveld op een account",
"salesforce_option": "Salesforce-optie",
"lookup_field_name": "Zoekveldnaam",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Voeg uw nieuwe strings hierboven toe ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Handling Påkrevd: Vennligst book en ny tid for {{eventType}} med {{name}}",
"hi_user_name": "Hei {{name}}",
"ics_event_title": "{{eventType}} med {{name}}",
"please_book_a_time_sometime_later": "Oops, vi kunne ikke koble deg til denne gangen. Vennligst planlegg en samtale senere.",
"please_book_a_time_sometime_later": "Det ser ut til at alle våre eksperter er opptatt akkurat nå. Vennligst planlegg en samtale på et tidspunkt som passer best for deg, så vil vi være klare til å hjelpe deg.",
"schedule_instead": "Planlegg i stedet",
"new_event_subject": "Ny hendelse: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Bli med via {{entryPoint}}",
"notes": "Notater",
@@ -350,9 +351,13 @@
"other": "Annet",
"email_sign_in_subject": "Påloggings-lenken din for {{appName}}",
"round_robin_emailed_you_and_attendees": "Du skal møte med {{user}}. Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle.",
"round_robin_emailed_host_and_attendee": "{{host}} møter {{attendee}}. Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle.",
"emailed_you_and_attendees": "Vi sendte deg og de andre deltakerne en kalenderinvitasjon med alle detaljene.",
"emailed_host_and_attendee": "Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle.",
"emailed_you_and_attendees_recurring": "Vi sendte deg og de andre deltakerne en kalenderinvitasjon på e-post for den første av disse gjentakende hendelsene.",
"round_robin_emailed_you_and_attendees_recurring": "Du skal møte med {{user}}. Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle for den første av disse gjentakende hendelsene.",
"emailed_host_and_attendee_recurring": "Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle for den første av disse gjentakende hendelsene.",
"round_robin_emailed_you_and_attendees_recurring": "Du møter {{user}}. Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle for den første av disse gjentakende hendelsene.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} møter {{attendee}}. Vi har sendt en e-post med en kalenderinvitasjon med detaljene til alle for den første av disse gjentakende hendelsene.",
"emailed_you_and_any_other_attendees": "Du og eventuelle andre deltakere har fått e-post med denne informasjonen.",
"needs_to_be_confirmed_or_rejected": "Bookingen din må fortsatt bekreftes eller avvises.",
"needs_to_be_confirmed_or_rejected_recurring": "Ditt gjentakende møte må fortsatt bekreftes eller avvises.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefonnummer vil bli oppgitt",
"before_event_trigger": "før hendelsen starter",
"event_cancelled_trigger": "når arrangementet er avlyst",
"after_hosts_cal_video_no_show": "Etter at verter ikke blir med på cal video",
"after_guests_cal_video_no_show": "Etter at gjester ikke blir med på cal video",
"after_hosts_cal_video_no_show": "Etter at vertene ikke møtte opp til cal-videoen",
"after_guests_cal_video_no_show": "Etter at gjestene ikke møtte opp til cal-videoen",
"new_event_trigger": "når en ny hendelse er booket",
"email_host_action": "send e-post til vert",
"email_attendee_action": "send e-post til deltakere",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Velg noen tilgjengelige tider og legg dem inn i e-posten din",
"select_time": "Velg tid",
"select_date": "Velg dato",
"connecting_you_to_someone": "Vi kobler deg til noen.",
"connecting_you_to_someone": "Vi kobler deg til noen fra {{orgName}}.",
"please_do_not_close_this_tab": "Vennligst ikke lukk eller oppdater denne siden",
"see_all_available_times": "Se alle tilgjengelige tider",
"org_team_names_example_1": "f.eks. Markedsføringsteam",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Hendelsens sluttid i deltakers tidssone",
"salesforce_create_event_on_contact": "Opprett hendelse på kontakt, hvis den eksisterer. Ellers faller tilbake til lead",
"salesforce_owner_name_to_change": "Eiernavn som skal endres",
"dont_have_access_this_page": "Du har ikke tilgang til denne siden",
"you_need_admin_or_owner_privileges_to_access": "For å se eller bruke denne siden, må du ha administrator- eller eierrettigheter",
"field_type": "Felttype",
"when_to_write": "Når skal det skrives",
"salesforce_on_booking_write_to_record": "Ved booking, skriv til et tilpasset felt på deltaker-{{record}}-posten",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Bookingstart-dato",
"booking_created_date": "Dato for opprettet booking",
"booking_reassigned_to_host": "Booking omfordelt til {{host}}",
"access_denied": "Tilgang nektet",
"salesforce_route_to_owner": "Kontaktens eier vil være Round Robin-vert hvis tilgjengelig",
"salesforce_do_not_route_to_owner": "Kontaktens eier vil ikke bli tvunget (kan fortsatt være vert hvis det samsvarer med attributtene og Round Robin-kriteriene)",
"salesforce_route_to_custom_lookup_field": "Rute til en bruker som samsvarer med et oppslagsfelt på en konto",
"salesforce_option": "Salesforce-alternativ",
"lookup_field_name": "Oppslagsfeltnavn",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Legg til dine nye strenger over her ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Działanie wymagało zmiany harmonogramu: Zarezerwuj nową godzinę na wydarzenie {{eventType}} z {{name}}",
"hi_user_name": "Cześć {{name}}",
"ics_event_title": "{{eventType}} z {{name}}",
"please_book_a_time_sometime_later": "Ups, nie udało się połączyć tym razem. Proszę zaplanować rozmowę na późniejszy termin.",
"please_book_a_time_sometime_later": "Wygląda na to, że wszyscy nasi eksperci są teraz zajęci. Proszę umówić się na rozmowę w dogodnym dla siebie terminie, a my będziemy gotowi, aby Ci pomóc.",
"schedule_instead": "Umów się zamiast tego",
"new_event_subject": "Nowe wydarzenie: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Dołącz przez {{entryPoint}}",
"notes": "Uwagi",
@@ -350,9 +351,13 @@
"other": "Inne",
"email_sign_in_subject": "Twój link logowania do aplikacji {{appName}}",
"round_robin_emailed_you_and_attendees": "Spotykasz się z {{user}}. Wysłaliśmy e-mail z zaproszeniem do kalendarza i szczegółami do wszystkich.",
"round_robin_emailed_host_and_attendee": "{{host}} spotka się z {{attendee}}. Wysłaliśmy do wszystkich email z zaproszeniem kalendarzowym zawierającym szczegóły.",
"emailed_you_and_attendees": "Wysłaliśmy Ci i innym uczestnikom zaproszenie do kalendarza ze wszystkimi szczegółami.",
"emailed_host_and_attendee": "Wysłaliśmy do wszystkich email z zaproszeniem kalendarzowym zawierającym szczegóły.",
"emailed_you_and_attendees_recurring": "Wysłaliśmy Ci oraz innym uczestnikom zaproszenie do kalendarza dotyczące pierwszego z tych cyklicznych wydarzeń.",
"round_robin_emailed_you_and_attendees_recurring": "Spotykasz się z {{user}}. Wysłaliśmy e-mail z zaproszeniem do kalendarza i szczegółami do wszystkich na pierwsze z tych cyklicznych wydarzeń.",
"emailed_host_and_attendee_recurring": "Wysłaliśmy do wszystkich email z zaproszeniem kalendarzowym zawierającym szczegóły pierwszego z serii cyklicznych spotkań.",
"round_robin_emailed_you_and_attendees_recurring": "Spotkasz się z {{user}}. Wysłaliśmy do wszystkich email z zaproszeniem kalendarzowym zawierającym szczegóły pierwszego z serii cyklicznych spotkań.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} spotka się z {{attendee}}. Wysłaliśmy do wszystkich email z zaproszeniem kalendarzowym zawierającym szczegóły pierwszego z serii cyklicznych spotkań.",
"emailed_you_and_any_other_attendees": "Ty i inni uczestnicy dostali e-mail z tymi informacjami.",
"needs_to_be_confirmed_or_rejected": "Twoja rezerwacja musi zostać potwierdzona lub odrzucona.",
"needs_to_be_confirmed_or_rejected_recurring": "Twoje spotkanie cykliczne musi jeszcze zostać potwierdzone lub odrzucone.",
@@ -1242,8 +1247,8 @@
"number_provided": "Numer telefonu zostanie podany.",
"before_event_trigger": "przed rozpoczęciem wydarzenia",
"event_cancelled_trigger": "gdy wydarzenie zostanie anulowane",
"after_hosts_cal_video_no_show": "Po tym, jak gospodarze nie dołączą do wideo na Cal",
"after_guests_cal_video_no_show": "Po tym, jak goście nie dołączą do wideo na Cal",
"after_hosts_cal_video_no_show": "Po tym, jak gospodarze nie dołączyli do rozmowy wideo",
"after_guests_cal_video_no_show": "Po tym, jak goście nie dołączyli do rozmowy wideo",
"new_event_trigger": "gdy nowe wydarzenie zostanie zarezerwowane",
"email_host_action": "wyślij wiadomość e-mail do hosta",
"email_attendee_action": "wyślij wiadomość e-mail do uczestników",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Wybierz kilka dostępnych terminów i osadź je w wiadomości e-mail",
"select_time": "Wybierz godzinę",
"select_date": "Wybierz datę",
"connecting_you_to_someone": "Łączymy Cię z kimś.",
"connecting_you_to_someone": "Łączymy Cię z kimś z {{orgName}}.",
"please_do_not_close_this_tab": "Proszę nie zamykać ani nie odświeżać tej strony",
"see_all_available_times": "Zobacz wszystkie dostępne godziny",
"org_team_names_example_1": "np. zespół marketingowy",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Czas zakończenia wydarzenia w strefie czasowej uczestnika",
"salesforce_create_event_on_contact": "Utwórz wydarzenie na kontakcie, jeśli istnieje. W przeciwnym razie użyj leada",
"salesforce_owner_name_to_change": "Nazwa właściciela do zmiany",
"dont_have_access_this_page": "Nie masz dostępu do tej strony",
"you_need_admin_or_owner_privileges_to_access": "Aby wyświetlić lub korzystać z tej strony, musisz mieć uprawnienia administratora lub właściciela",
"field_type": "Typ pola",
"when_to_write": "Kiedy zapisać",
"salesforce_on_booking_write_to_record": "Przy rezerwacji, zapisz do niestandardowego pola w rekordzie {{record}} uczestnika",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Data rozpoczęcia rezerwacji",
"booking_created_date": "Data utworzenia rezerwacji",
"booking_reassigned_to_host": "Rezerwacja przypisana ponownie do {{host}}",
"access_denied": "Odmowa dostępu",
"salesforce_route_to_owner": "Właściciel kontaktu będzie hostem Round Robin, jeśli jest dostępny",
"salesforce_do_not_route_to_owner": "Właściciel kontaktu nie będzie wymuszony (może nadal być hostem, jeśli spełnia atrybuty i kryteria Round Robin)",
"salesforce_route_to_custom_lookup_field": "Przekieruj do użytkownika, który odpowiada polu wyszukiwania w koncie",
"salesforce_option": "Opcja Salesforce",
"lookup_field_name": "Nazwa pola wyszukiwania",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Dodaj nowe ciągi powyżej ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Ação de reagendamento necessária: reserve outro horário para {{eventType}} com {{name}}",
"hi_user_name": "Olá {{name}}",
"ics_event_title": "{{eventType}} com {{name}}",
"please_book_a_time_sometime_later": "Ops, não foi possível conectá-lo desta vez. Por favor, agende uma chamada mais tarde",
"please_book_a_time_sometime_later": "Parece que todos os nossos especialistas estão ocupados no momento. Por favor, agende uma chamada em um horário que seja mais conveniente para você e estaremos prontos para ajudar.",
"schedule_instead": "Agendar agora",
"new_event_subject": "Novo evento: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Junte-se através de {{entryPoint}}",
"notes": "Notas",
@@ -350,9 +351,13 @@
"other": "Outras",
"email_sign_in_subject": "Seu link de login para {{appName}}",
"round_robin_emailed_you_and_attendees": "Você está reunindo-se com {{user}}. Nós enviamos um e-mail com um convite de calendário com todos os detalhes para todos.",
"round_robin_emailed_host_and_attendee": "{{host}} terá uma reunião com {{attendee}}. Enviamos um e-mail com um convite para o calendário contendo todos os detalhes para todos os participantes.",
"emailed_you_and_attendees": "Enviamos um e-mail para você e para os outros participantes com um convite de calendário com todos os detalhes.",
"emailed_host_and_attendee": "Enviamos um e-mail com um convite para o calendário contendo todos os detalhes para todos os participantes.",
"emailed_you_and_attendees_recurring": "Enviamos um e-mail para você e para os outros participantes com um convite de calendário para o primeiro desses eventos recorrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Você está reunindo-se com {{user}}. Nós enviamos um e-mail com um convite de calendário com todos os detalhes para todos com o primeiro destes eventos recorrentes.",
"emailed_host_and_attendee_recurring": "Enviamos um e-mail com um convite para o calendário contendo todos os detalhes para todos os participantes para o primeiro destes eventos recorrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Você terá uma reunião com {{user}}. Enviamos um e-mail com um convite para o calendário contendo todos os detalhes para todos os participantes para o primeiro destes eventos recorrentes.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} terá uma reunião com {{attendee}}. Enviamos um e-mail com um convite para o calendário contendo todos os detalhes para todos os participantes para o primeiro destes eventos recorrentes.",
"emailed_you_and_any_other_attendees": "Esta informação foi enviada para você e para todos os outros participantes.",
"needs_to_be_confirmed_or_rejected": "A sua reserva ainda precisa de ser confirmada ou recusada.",
"needs_to_be_confirmed_or_rejected_recurring": "A sua reunião recorrente ainda precisa ser confirmada ou recusada.",
@@ -1242,8 +1247,8 @@
"number_provided": "O número de telefone será fornecido",
"before_event_trigger": "antes do início do evento",
"event_cancelled_trigger": "quando o evento for cancelado",
"after_hosts_cal_video_no_show": "Após os anfitriões não entrarem no vídeo do Cal",
"after_guests_cal_video_no_show": "Após os convidados não entrarem no vídeo do Cal",
"after_hosts_cal_video_no_show": "Após os anfitriões não entrarem na videochamada do Cal",
"after_guests_cal_video_no_show": "Após os convidados não entrarem na videochamada do Cal",
"new_event_trigger": "quando um novo evento for reservado",
"email_host_action": "enviar e-mail para a(o) anfitriã(o)",
"email_attendee_action": "enviar e-mail aos participantes",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Selecione alguns horários disponíveis e incorpore-os no seu e-mail",
"select_time": "Selecione o horário",
"select_date": "Selecione a data",
"connecting_you_to_someone": "Estamos conectando você a alguém.",
"connecting_you_to_someone": "Estamos conectando você a alguém da {{orgName}}.",
"please_do_not_close_this_tab": "Por favor, não feche ou atualize esta página",
"see_all_available_times": "Veja todos os horários disponíveis",
"org_team_names_example_1": "ex.: Time de Marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Hora de término do evento no fuso horário do participante",
"salesforce_create_event_on_contact": "Criar evento no contato, se existir. Caso contrário, usar lead como alternativa",
"salesforce_owner_name_to_change": "Nome do proprietário a ser alterado",
"dont_have_access_this_page": "Você não tem acesso a esta página",
"you_need_admin_or_owner_privileges_to_access": "Para visualizar ou interagir com esta página, você deve ter privilégios de administrador ou proprietário",
"field_type": "Tipo de campo",
"when_to_write": "Quando escrever",
"salesforce_on_booking_write_to_record": "Ao fazer uma reserva, escrever em um campo personalizado no registro {{record}} do participante",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Data de início da reserva",
"booking_created_date": "Data de criação da reserva",
"booking_reassigned_to_host": "Reserva reatribuída para {{host}}",
"access_denied": "Acesso negado",
"salesforce_route_to_owner": "O proprietário do contato será o anfitrião do Round Robin se disponível",
"salesforce_do_not_route_to_owner": "O proprietário do contato não será forçado (ainda pode ser anfitrião se corresponder aos atributos e critérios do Round Robin)",
"salesforce_route_to_custom_lookup_field": "Direcionar para um usuário que corresponda a um campo de pesquisa em uma conta",
"salesforce_option": "Opção do Salesforce",
"lookup_field_name": "Nome do campo de pesquisa",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adicione suas novas strings aqui em cima ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Acção necessária para reagendamento: Por favor reserve uma nova hora para {{eventType}} com {{name}}",
"hi_user_name": "Olá {{name}}",
"ics_event_title": "{{eventType}} com {{name}}",
"please_book_a_time_sometime_later": "Ninguém estava disponível no momento. Por favor, faça uma reserva para um horário mais tarde",
"please_book_a_time_sometime_later": "Parece que todos os nossos especialistas estão ocupados no momento. Por favor, agende uma chamada em um horário que seja melhor para você e estaremos prontos para ajudá-lo.",
"schedule_instead": "Agendar em vez disso",
"new_event_subject": "Novo evento: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Junte-se através de {{entryPoint}}",
"notes": "Notas",
@@ -350,9 +351,13 @@
"other": "Outras",
"email_sign_in_subject": "A sua ligação de início de sessão para {{appName}}",
"round_robin_emailed_you_and_attendees": "Está a reunir com {{user}}. Enviámos um e-mail para si e para os outros participantes com um convite de calendário com todos os detalhes.",
"round_robin_emailed_host_and_attendee": "{{host}} terá uma reunião com {{attendee}}. Enviamos um e-mail com um convite para o calendário contendo todos os detalhes.",
"emailed_you_and_attendees": "Enviámos um email para si e para os outros participantes com um convite de calendário com todos os detalhes.",
"emailed_host_and_attendee": "Enviamos um e-mail com um convite para o calendário contendo todos os detalhes.",
"emailed_you_and_attendees_recurring": "Enviámos um email para si e para os outros participantes com um convite de calendário para o primeiro destes eventos recorrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Está a reunir com {{user}}. Enviámos um e-mail para si e para os outros participantes com um convite de calendário para o primeiro destes eventos recorrentes.",
"emailed_host_and_attendee_recurring": "Enviamos um e-mail com um convite para o calendário contendo os detalhes do primeiro destes eventos recorrentes.",
"round_robin_emailed_you_and_attendees_recurring": "Você terá uma reunião com {{user}}. Enviamos um e-mail com um convite para o calendário contendo os detalhes do primeiro destes eventos recorrentes.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} terá uma reunião com {{attendee}}. Enviamos um e-mail com um convite para o calendário contendo os detalhes do primeiro destes eventos recorrentes.",
"emailed_you_and_any_other_attendees": "Esta informação foi enviada para si e para todos os outros participantes.",
"needs_to_be_confirmed_or_rejected": "A sua reserva ainda precisa de ser confirmada ou rejeitada.",
"needs_to_be_confirmed_or_rejected_recurring": "A sua reunião recorrente ainda precisa de ser confirmada ou rejeitada.",
@@ -1242,8 +1247,8 @@
"number_provided": "Será fornecido um número de telefone",
"before_event_trigger": "antes do evento iniciar",
"event_cancelled_trigger": "quando o evento for cancelado",
"after_hosts_cal_video_no_show": "Após os anfitriões não se juntarem ao vídeo do Cal",
"after_guests_cal_video_no_show": "Após os convidados não se juntarem ao vídeo do Cal",
"after_hosts_cal_video_no_show": "Após os anfitriões não terem participado do vídeo do Cal",
"after_guests_cal_video_no_show": "Após os convidados não terem participado do vídeo do Cal",
"new_event_trigger": "quando um novo evento for reservado",
"email_host_action": "enviar email ao anfitrião",
"email_attendee_action": "enviar e-mail aos participantes",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Selecione alguns horários disponíveis e incorpore-os no seu E-mail",
"select_time": "Selecionar horário",
"select_date": "Selecionar data",
"connecting_you_to_someone": "Estamos a conectá-lo a alguém.",
"connecting_you_to_someone": "Estamos conectando você a alguém da {{orgName}}.",
"please_do_not_close_this_tab": "Por favor, não feche ou atualize esta página",
"see_all_available_times": "Ver todos os horários disponíveis",
"org_team_names_example_1": "Por exemplo, Equipa de Marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Hora de fim do evento no fuso horário do participante",
"salesforce_create_event_on_contact": "Criar evento no contacto, se existir. Caso contrário, recorrer ao lead",
"salesforce_owner_name_to_change": "Nome do proprietário a alterar",
"dont_have_access_this_page": "Você não tem acesso a esta página",
"you_need_admin_or_owner_privileges_to_access": "Para visualizar ou interagir com esta página, você deve ter privilégios de administrador ou proprietário",
"field_type": "Tipo de campo",
"when_to_write": "Quando escrever",
"salesforce_on_booking_write_to_record": "Na reserva, escrever num campo personalizado no registo {{record}} do participante",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Data de início da reserva",
"booking_created_date": "Data de criação da reserva",
"booking_reassigned_to_host": "Reserva reatribuída a {{host}}",
"access_denied": "Acesso negado",
"salesforce_route_to_owner": "O proprietário do contato será o anfitrião do Round Robin se disponível",
"salesforce_do_not_route_to_owner": "O proprietário do contato não será forçado (ainda pode ser anfitrião se corresponder aos atributos e critérios do Round Robin)",
"salesforce_route_to_custom_lookup_field": "Direcionar para um usuário que corresponda a um campo de pesquisa em uma conta",
"salesforce_option": "Opção do Salesforce",
"lookup_field_name": "Nome do campo de pesquisa",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Acțiunea necesită reprogramare: rezervați o nouă dată pentru {{eventType}} cu {{name}}",
"hi_user_name": "Salut {{name}}",
"ics_event_title": "{{eventType}} cu {{name}}",
"please_book_a_time_sometime_later": "Ups, nu te-am putut conecta de această dată. Te rugăm să programezi un apel pentru o dată viitoare.",
"please_book_a_time_sometime_later": "Se pare că toți experții noștri sunt ocupați în acest moment. Vă rugăm să programați un apel la un moment care vi se potrivește cel mai bine și vom fi pregătiți să vă asistăm.",
"schedule_instead": "Programați în schimb",
"new_event_subject": "Eveniment nou: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Alăturați-vă de {{entryPoint}}",
"notes": "Notiţe",
@@ -350,9 +351,13 @@
"other": "Altele",
"email_sign_in_subject": "Linkul tău de conectare pentru {{appName}}",
"round_robin_emailed_you_and_attendees": "Te întâlnești cu {{user}}. Am trimis un email cu o invitație în calendar cu detaliile către toți participanții.",
"round_robin_emailed_host_and_attendee": "{{host}} se întâlnește cu {{attendee}}. Am trimis un email cu o invitație în calendar cu detaliile către toată lumea.",
"emailed_you_and_attendees": "V-am trimis un e-mail dumneavoastră şi celuilalt participant la o invitaţie în calendar cu toate detaliile.",
"emailed_host_and_attendee": "Am trimis un email cu o invitație în calendar cu detaliile către toată lumea.",
"emailed_you_and_attendees_recurring": "V-am trimis un e-mail dvs. și celorlalți participanți cu o invitație în calendar pentru primul dintre aceste evenimente recurente.",
"round_robin_emailed_you_and_attendees_recurring": "Te întâlnești cu {{user}}. Am trimis un email cu o invitație în calendar cu detaliile către toți participanții pentru primul dintre aceste evenimente recurente.",
"emailed_host_and_attendee_recurring": "Am trimis un email cu o invitație în calendar cu detaliile către toată lumea pentru primul dintre aceste evenimente recurente.",
"round_robin_emailed_you_and_attendees_recurring": "Te întâlnești cu {{user}}. Am trimis un email cu o invitație în calendar cu detaliile către toată lumea pentru primul dintre aceste evenimente recurente.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} se întâlnește cu {{attendee}}. Am trimis un email cu o invitație în calendar cu detaliile către toată lumea pentru primul dintre aceste evenimente recurente.",
"emailed_you_and_any_other_attendees": "Dumneavoastră şi oricare alţi participanţi aţi primit prin e-mail aceste informaţii.",
"needs_to_be_confirmed_or_rejected": "Rezervarea dvs. încă trebuie confirmată sau respinsă.",
"needs_to_be_confirmed_or_rejected_recurring": "Întâlnirea dvs. recurentă încă trebuie confirmată sau respinsă.",
@@ -1242,8 +1247,8 @@
"number_provided": "Numărul de telefon va fi furnizat",
"before_event_trigger": "înainte de începerea evenimentului",
"event_cancelled_trigger": "la anularea evenimentului",
"after_hosts_cal_video_no_show": "După ce gazdele nu se alătură la cal video",
"after_guests_cal_video_no_show": "După ce invitații nu se alătură la cal video",
"after_hosts_cal_video_no_show": "După ce gazdele nu s-au alăturat la cal video",
"after_guests_cal_video_no_show": "După ce oaspeții nu s-au alăturat la cal video",
"new_event_trigger": "când este rezervat noul eveniment",
"email_host_action": "trimiteți e-mail la gazdă",
"email_attendee_action": "trimiteți e-mail participanților",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Selectați câteva date disponibile și încorporați-le în e-mailul dvs.",
"select_time": "Selectați ora",
"select_date": "Selectați data",
"connecting_you_to_someone": "Te conectăm cu cineva.",
"connecting_you_to_someone": "Vă conectăm cu cineva de la {{orgName}}.",
"please_do_not_close_this_tab": "Vă rugăm să nu închideți sau să reîmprospătați această pagină",
"see_all_available_times": "Vedeți toate orele disponibile",
"org_team_names_example_1": "de ex. echipa de marketing",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Ora de sfârșit a evenimentului în fusul orar al participantului",
"salesforce_create_event_on_contact": "Creați evenimentul pe contact, dacă există. Altfel, reveniți la lead",
"salesforce_owner_name_to_change": "Numele proprietarului de schimbat",
"dont_have_access_this_page": "Nu aveți acces la această pagină",
"you_need_admin_or_owner_privileges_to_access": "Pentru a vizualiza sau interacționa cu această pagină, trebuie să aveți privilegii de administrator sau proprietar",
"field_type": "Tip câmp",
"when_to_write": "Când să se scrie",
"salesforce_on_booking_write_to_record": "La rezervare, scrie într-un câmp personalizat în înregistrarea {{record}} a participantului",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Data de început a rezervării",
"booking_created_date": "Data creării rezervării",
"booking_reassigned_to_host": "Rezervare reatribuită către {{host}}",
"access_denied": "Acces refuzat",
"salesforce_route_to_owner": "Proprietarul contactului va fi gazda Round Robin dacă este disponibil",
"salesforce_do_not_route_to_owner": "Proprietarul contactului nu va fi forțat (poate fi totuși gazdă dacă se potrivesc atributele și criteriile Round Robin)",
"salesforce_route_to_custom_lookup_field": "Redirecționează către un utilizator care se potrivește cu un câmp de căutare pe un cont",
"salesforce_option": "Opțiune Salesforce",
"lookup_field_name": "Nume câmp de căutare",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Adăugați stringurile noi deasupra acestui rând ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Promena vremena zahteva radnju: zakažite novo vreme za {{eventType}} sa {{name}}",
"hi_user_name": "Zdravo {{name}}",
"ics_event_title": "{{eventType}} sa {{name}}",
"please_book_a_time_sometime_later": "Ups, nismo uspeli da vas povežemo ovaj put. Molimo vas da zakažete poziv za kasnije.",
"please_book_a_time_sometime_later": "Izgleda da su svi naši stručnjaci trenutno zauzeti. Molimo vas da zakažete poziv u vreme koje vam najviše odgovara i bićemo spremni da vam pomognemo.",
"schedule_instead": "Zakažite umesto toga",
"new_event_subject": "Novi dogadjaj: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Pridruži se putem {{entryPoint}}",
"notes": "Beleške",
@@ -350,9 +351,13 @@
"other": "Drugo",
"email_sign_in_subject": "Vaša veza za prijavu na {{appName}}",
"round_robin_emailed_you_and_attendees": "Sastajete se sa {{user}}. Poslali smo email sa pozivom na kalendar sa detaljima svima.",
"round_robin_emailed_host_and_attendee": "{{host}} se sastaje sa {{attendee}}. Poslali smo e-mail sa pozivnicom za kalendar sa detaljima svima.",
"emailed_you_and_attendees": "Poslali smo vama i ostalim učesnicima kalendarski poziv sa svim detaljima.",
"emailed_host_and_attendee": "Poslali smo e-mail sa pozivnicom za kalendar sa detaljima svima.",
"emailed_you_and_attendees_recurring": "Poslali smo vama i ostalim učesnicima kalendarski poziv za prvi od ovih ponavljajućih događaja.",
"round_robin_emailed_you_and_attendees_recurring": "Sastajete se sa {{user}}. Poslali smo email sa pozivom na kalendar sa detaljima svima za prvi od ovih ponavljajućih događaja.",
"emailed_host_and_attendee_recurring": "Poslali smo e-mail sa pozivnicom za kalendar sa detaljima svima za prvi od ovih ponavljajućih događaja.",
"round_robin_emailed_you_and_attendees_recurring": "Sastajete se sa {{user}}. Poslali smo e-mail sa pozivnicom za kalendar sa detaljima svima za prvi od ovih ponavljajućih događaja.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} se sastaje sa {{attendee}}. Poslali smo e-mail sa pozivnicom za kalendar sa detaljima svima za prvi od ovih ponavljajućih događaja.",
"emailed_you_and_any_other_attendees": "Vi i ostali učesnici ste dobili e-poštu sa ovim informacijama.",
"needs_to_be_confirmed_or_rejected": "Vaša rezervicija i dalje mora da se potrvrdi ili odbije.",
"needs_to_be_confirmed_or_rejected_recurring": "Vaš ponavljajući sastanak i dalje mora da se potvrdi ili odbije.",
@@ -1242,8 +1247,8 @@
"number_provided": "Broj telefona će biti dostavljen",
"before_event_trigger": "pre početka događaja",
"event_cancelled_trigger": "kada je događaj otkazan",
"after_hosts_cal_video_no_show": "Nakon što se domaćini ne pojave na Cal video sastanku",
"after_guests_cal_video_no_show": "Nakon što se gosti ne pojave na Cal video sastanku",
"after_hosts_cal_video_no_show": "Nakon što se domaćini nisu pojavili na cal video pozivu",
"after_guests_cal_video_no_show": "Nakon što se gosti nisu pojavili na cal video pozivu",
"new_event_trigger": "kada je zakazan novi događaj",
"email_host_action": "pošalji imejl domaćinu",
"email_attendee_action": "pošalji imejl učesnicima",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Izaberite nekoliko dostupnih termina i ugradite ih u svoj imejl",
"select_time": "Izaberite vreme",
"select_date": "Izaberite datum",
"connecting_you_to_someone": "Povezujemo vas sa nekim.",
"connecting_you_to_someone": "Povezujemo vas sa nekim iz {{orgName}}.",
"please_do_not_close_this_tab": "Молимо вас да не затварате или освежавате ову страницу",
"see_all_available_times": "Pogledajte sva dostupna vremena",
"org_team_names_example_1": "npr. Marketing tim",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Vreme završetka događaja u vremenskoj zoni učesnika",
"salesforce_create_event_on_contact": "Kreiraj događaj na kontaktu, ako postoji. U suprotnom, prebaci na lead",
"salesforce_owner_name_to_change": "Ime vlasnika koje treba promeniti",
"dont_have_access_this_page": "Nemate pristup ovoj stranici",
"you_need_admin_or_owner_privileges_to_access": "Da biste pregledali ili koristili ovu stranicu, morate imati administratorske ili vlasničke privilegije",
"field_type": "Tip polja",
"when_to_write": "Kada pisati",
"salesforce_on_booking_write_to_record": "Pri rezervaciji, upiši u prilagođeno polje na {{record}} zapisu učesnika",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Datum početka rezervacije",
"booking_created_date": "Datum kreiranja rezervacije",
"booking_reassigned_to_host": "Rezervacija dodeljena {{host}}-u",
"access_denied": "Pristup odbijen",
"salesforce_route_to_owner": "Vlasnik kontakta će biti Round Robin domaćin ako je dostupan",
"salesforce_do_not_route_to_owner": "Vlasnik kontakta neće biti primoran (može i dalje biti domaćin ako odgovara atributima i Round Robin kriterijumima)",
"salesforce_route_to_custom_lookup_field": "Usmeri ka korisniku koji odgovara polju za pretragu na nalogu",
"salesforce_option": "Salesforce opcija",
"lookup_field_name": "Naziv polja za pretragu",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Dodajte svoje nove stringove iznad ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Åtgärd som krävs Tidsschema: Boka en ny tid för {{eventType}} hos {{name}}",
"hi_user_name": "Hej {{name}}",
"ics_event_title": "{{eventType}} med {{name}}",
"please_book_a_time_sometime_later": "Oj, vi kunde inte ansluta dig den här gången. Vänligen boka ett framtida samtal istället.",
"please_book_a_time_sometime_later": "Det verkar som att alla våra experter är upptagna just nu. Vänligen boka ett samtal vid en tidpunkt som passar dig bäst, så hjälper vi dig då.",
"schedule_instead": "Boka istället",
"new_event_subject": "Ny bokning: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Anslut med {{entryPoint}}",
"notes": "Anteckningar",
@@ -350,9 +351,13 @@
"other": "Annat",
"email_sign_in_subject": "Din inloggningslänk för {{appName}}",
"round_robin_emailed_you_and_attendees": "Du möter {{user}}. Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla.",
"round_robin_emailed_host_and_attendee": "{{host}} träffar {{attendee}}. Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla.",
"emailed_you_and_attendees": "Vi skickade dig och de andra deltagarna en kalenderinbjudan med alla detaljer.",
"emailed_host_and_attendee": "Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla.",
"emailed_you_and_attendees_recurring": "Vi skickade dig och de andra deltagarna en kalenderinbjudan via e-post för den första av dessa återkommande händelser.",
"round_robin_emailed_you_and_attendees_recurring": "Du möter {{user}}. Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla för det första av dessa återkommande evenemang.",
"emailed_host_and_attendee_recurring": "Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla för det första av dessa återkommande evenemang.",
"round_robin_emailed_you_and_attendees_recurring": "Du träffar {{user}}. Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla för det första av dessa återkommande evenemang.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} träffar {{attendee}}. Vi har skickat ett e-postmeddelande med en kalenderinbjudan med detaljerna till alla för det första av dessa återkommande evenemang.",
"emailed_you_and_any_other_attendees": "Du och alla andra deltagare har fått e-post med denna information.",
"needs_to_be_confirmed_or_rejected": "Din bokning behöver fortfarande bekräftas eller avböjas.",
"needs_to_be_confirmed_or_rejected_recurring": "Ditt återkommande möte behöver fortfarande bekräftas eller avböjas.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefonnummer kommer att anges",
"before_event_trigger": "innan händelsen startar",
"event_cancelled_trigger": "när händelsen ställs in",
"after_hosts_cal_video_no_show": "Efter att värdarna inte ansluter till cal video",
"after_guests_cal_video_no_show": "Efter att gästerna inte ansluter till cal video",
"after_hosts_cal_video_no_show": "Efter att värdarna inte deltog i cal-video",
"after_guests_cal_video_no_show": "Efter att gästerna inte deltog i cal-video",
"new_event_trigger": "när ny händelse bokas",
"email_host_action": "skicka e-post till värd",
"email_attendee_action": "skicka e-post till deltagare",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Välj några tillgängliga tider och bädda in dem i din e-post",
"select_time": "Välj tid",
"select_date": "Välj datum",
"connecting_you_to_someone": "Vi kopplar dig till någon.",
"connecting_you_to_someone": "Vi kopplar dig till någon från {{orgName}}.",
"please_do_not_close_this_tab": "Vänligen stäng eller uppdatera inte den här sidan",
"see_all_available_times": "Se alla tillgängliga tider",
"org_team_names_example_1": "t.ex. marknadsföringsteam",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Händelsens sluttid i deltagarens tidszon",
"salesforce_create_event_on_contact": "Skapa händelse på kontakt om den finns, annars fallback till lead",
"salesforce_owner_name_to_change": "Ägarnamn att ändra",
"dont_have_access_this_page": "Du har inte åtkomst till den här sidan",
"you_need_admin_or_owner_privileges_to_access": "För att visa eller interagera med den här sidan måste du ha administratörs- eller ägarprivilegier",
"field_type": "Fälttyp",
"when_to_write": "När ska det skrivas",
"salesforce_on_booking_write_to_record": "Vid bokning, skriv till ett anpassat fält på deltagarens {{record}}-post",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Bokningens startdatum",
"booking_created_date": "Bokningens skapandedatum",
"booking_reassigned_to_host": "Bokning omtilldelad till {{host}}",
"access_denied": "Åtkomst nekad",
"salesforce_route_to_owner": "Kontaktägaren blir Round Robin-värd om tillgänglig",
"salesforce_do_not_route_to_owner": "Kontaktägaren kommer inte att tvingas (kan fortfarande vara värd om det matchar attributen och Round Robin-kriterierna)",
"salesforce_route_to_custom_lookup_field": "Rikta till en användare som matchar ett uppslagsfält på ett konto",
"salesforce_option": "Salesforce-alternativ",
"lookup_field_name": "Uppslagsfältsnamn",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Yeniden Planlama İşlemi Gerekiyor: Lütfen {{name}} ile {{eventType}} için yeni bir saat belirleyin",
"hi_user_name": "Merhaba {{name}}",
"ics_event_title": "{{name}} ile {{eventType}}",
"please_book_a_time_sometime_later": "Üzgünüz, bu sefer bağlanamadık. Lütfen ileri bir tarih için arama planlayın.",
"please_book_a_time_sometime_later": "Görünüşe göre şu anda tüm uzmanlarımız meşgul. Lütfen sizin için en uygun olan bir zamanda bir görüşme planlayın, biz de size yardımcı olmaya hazır olacağız.",
"schedule_instead": "Bunun yerine planla",
"new_event_subject": "Yeni etkinlik: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "{{entryPoint}} ile katıl",
"notes": "Notlar",
@@ -350,9 +351,13 @@
"other": "Diğer",
"email_sign_in_subject": "{{appName}} için giriş bağlantınız",
"round_robin_emailed_you_and_attendees": "{{user}} ile görüşüyorsunuz. Detayları içeren bir takvim davetiyesi e-postası herkese gönderildi.",
"round_robin_emailed_host_and_attendee": "{{host}}, {{attendee}} ile görüşecek. Herkese detayları içeren takvim davetiyesini e-posta ile gönderdik.",
"emailed_you_and_attendees": "Size ve diğer katılımcılara tüm ayrıntıları içeren bir takvim daveti e-postası gönderdik.",
"emailed_host_and_attendee": "Herkese detayları içeren takvim davetiyesini e-posta ile gönderdik.",
"emailed_you_and_attendees_recurring": "Size ve diğer katılımcılara bu yinelenen etkinliklerin ilki için bir takvim daveti e-postası gönderdik.",
"round_robin_emailed_you_and_attendees_recurring": "{{user}} ile görüşüyorsunuz. Bu tekrarlayan etkinliklerin ilki için detayları içeren bir takvim davetiyesi e-postası herkese gönderildi.",
"emailed_host_and_attendee_recurring": "Bu tekrarlanan etkinliklerin ilki için herkese detayları içeren takvim davetiyesini e-posta ile gönderdik.",
"round_robin_emailed_you_and_attendees_recurring": "{{user}} ile görüşeceksiniz. Bu tekrarlanan etkinliklerin ilki için herkese detayları içeren takvim davetiyesini e-posta ile gönderdik.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}}, {{attendee}} ile görüşecek. Bu tekrarlanan etkinliklerin ilki için herkese detayları içeren takvim davetiyesini e-posta ile gönderdik.",
"emailed_you_and_any_other_attendees": "Bu bilgiler size ve diğer katılımcılara e-posta ile gönderildi.",
"needs_to_be_confirmed_or_rejected": "Rezervasyonunuzun hâlâ onaylanması veya reddedilmesi gerekiyor.",
"needs_to_be_confirmed_or_rejected_recurring": "Yinelenen toplantınızın hâlâ onaylanması veya reddedilmesi gerekiyor.",
@@ -1242,8 +1247,8 @@
"number_provided": "Telefon numarası sağlanacaktır",
"before_event_trigger": "etkinlik başlamadan önce",
"event_cancelled_trigger": "etkinlik iptal edildiğinde",
"after_hosts_cal_video_no_show": "Ev sahipleri Cal video toplantısına katılmadığında",
"after_guests_cal_video_no_show": "Misafirler Cal video toplantısına katılmadığında",
"after_hosts_cal_video_no_show": "Ev sahipleri Cal görüntülü görüşmesine katılmadıktan sonra",
"after_guests_cal_video_no_show": "Misafirler Cal görüntülü görüşmesine katılmadıktan sonra",
"new_event_trigger": "yeni bir etkinlik için rezervasyon yapıldığında",
"email_host_action": "organizatöre e-posta gönder",
"email_attendee_action": "katılımcılara e-posta gönder",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Uygun zamanlardan bazılarını seçin ve bunları E-postanıza ekleyin",
"select_time": "Saati Seçin",
"select_date": "Tarihi Seçin",
"connecting_you_to_someone": "Sizi birine bağlıyoruz.",
"connecting_you_to_someone": "Sizi {{orgName}}'den birisiyle bağlıyoruz.",
"please_do_not_close_this_tab": "Lütfen bu sayfayı kapatmayın veya yenilemeyin",
"see_all_available_times": "Tüm müsait saatleri görün",
"org_team_names_example_1": "Örneğin. Pazarlama ekibi",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Katılımcı Saat Diliminde Etkinlik Bitiş Zamanı",
"salesforce_create_event_on_contact": "Eğer varsa, kişi üzerinde etkinlik oluştur. Yoksa potansiyel müşteriye geri dön",
"salesforce_owner_name_to_change": "Değiştirilecek sahip adı",
"dont_have_access_this_page": "Bu sayfaya erişiminiz yok",
"you_need_admin_or_owner_privileges_to_access": "Bu sayfayı görüntülemek veya etkileşimde bulunmak için yönetici veya sahip ayrıcalıklarına sahip olmalısınız",
"field_type": "Alan türü",
"when_to_write": "Ne zaman yazılacak",
"salesforce_on_booking_write_to_record": "Rezervasyon yapıldığında, katılımcının {{record}} kaydındaki özel alana yaz",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Rezervasyon başlangıç tarihi",
"booking_created_date": "Rezervasyon oluşturma tarihi",
"booking_reassigned_to_host": "Rezervasyon {{host}} kişisine yeniden atandı",
"access_denied": "Erişim Reddedildi",
"salesforce_route_to_owner": "Mümkünse kişi sahibi round robin ev sahibi olacak",
"salesforce_do_not_route_to_owner": "Kişi sahibi zorlanmayacak (özellikler ve round robin kriterlerine uyuyorsa yine de ev sahibi olabilir)",
"salesforce_route_to_custom_lookup_field": "Bir hesaptaki arama alanıyla eşleşen bir kullanıcıya yönlendir",
"salesforce_option": "Salesforce seçeneği",
"lookup_field_name": "Arama alanı adı",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Yeni dizelerinizi yukarıya ekleyin ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+17 -4
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Потрібно перенести бронювання: забронюйте новий час для заходу «{{eventType}}» із користувачем {{name}}",
"hi_user_name": "Привіт, {{name}}!",
"ics_event_title": "{{eventType}} «{{name}}»",
"please_book_a_time_sometime_later": "Ой, ми не можемо підключитися до вас цього разу. Будь ласка, організуйте майбутній дзвінок замість цього",
"please_book_a_time_sometime_later": "Схоже, що всі наші експерти зараз зайняті. Будь ласка, заплануйте дзвінок на зручний для вас час, і ми будемо готові вам допомогти.",
"schedule_instead": "Запланувати натомість",
"new_event_subject": "Новий захід: {{attendeeName}} – {{date}} – {{eventType}}",
"join_by_entrypoint": "Приєднатися через {{entryPoint}}",
"notes": "Примітки",
@@ -350,9 +351,13 @@
"other": "Інше",
"email_sign_in_subject": "Ваше посилання для входу в {{appName}}",
"round_robin_emailed_you_and_attendees": "Ви зустрічаєтеся з {{user}}. Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам.",
"round_robin_emailed_host_and_attendee": "{{host}} зустрічається з {{attendee}}. Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам.",
"emailed_you_and_attendees": "Ми надіслали вам та іншим учасникам запрошення до календаря з усіма деталями.",
"emailed_host_and_attendee": "Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам.",
"emailed_you_and_attendees_recurring": "Ми надіслали вам та іншим учасникам запрошення з календаря на перший із цих періодичних заходів.",
"emailed_host_and_attendee_recurring": "Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам для першої з цих повторюваних подій.",
"round_robin_emailed_you_and_attendees_recurring": "Ви зустрічаєтеся з {{user}}. Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам для першої з цих повторюваних подій.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} зустрічається з {{attendee}}. Ми надіслали електронний лист із запрошенням у календар з деталями всім учасникам для першої з цих повторюваних подій.",
"emailed_you_and_any_other_attendees": "Цю інформацію надіслано вам і всім іншим учасникам.",
"needs_to_be_confirmed_or_rejected": "Ваше бронювання досі потрібно підтвердити або відхилити.",
"needs_to_be_confirmed_or_rejected_recurring": "Вашу періодичну нараду досі потрібно підтвердити або відхилити.",
@@ -1242,8 +1247,8 @@
"number_provided": "Номер телефону буде надано",
"before_event_trigger": "до початку заходу",
"event_cancelled_trigger": "у момент скасування заходу",
"after_hosts_cal_video_no_show": "Після того, як господарі не приєдналися до відеозустрічі на Cal",
"after_guests_cal_video_no_show": "Після того, як гості не приєдналися до відеозустрічі на Cal",
"after_hosts_cal_video_no_show": "Після того, як організатори не приєдналися до відеодзвінка",
"after_guests_cal_video_no_show": "Після того, як гості не приєдналися до відеодзвінка",
"new_event_trigger": "у момент бронювання нового заходу",
"email_host_action": "надсилати електронний лист ведучому",
"email_attendee_action": "надіслати ел. лист учасникам",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Виберіть кілька доступних часових проміжків і вбудуйте їх в електронний лист",
"select_time": "Виберіть час",
"select_date": "Виберіть дату",
"connecting_you_to_someone": "Ми з'єднуємо вас з кимось.",
"connecting_you_to_someone": "Ми з'єднуємо вас із представником {{orgName}}.",
"please_do_not_close_this_tab": "Будь ласка, не закривайте і не оновлюйте цю сторінку",
"see_all_available_times": "Переглянути доступні часові проміжки",
"org_team_names_example_1": "напр. команда маркетингу",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Час закінчення події в часовому поясі учасника",
"salesforce_create_event_on_contact": "Створити подію для контакту, якщо він існує. В іншому випадку створити для ліда",
"salesforce_owner_name_to_change": "Ім'я власника для зміни",
"dont_have_access_this_page": "Ви не маєте доступу до цієї сторінки",
"you_need_admin_or_owner_privileges_to_access": "Щоб переглядати або взаємодіяти з цією сторінкою, ви повинні мати права адміністратора або власника",
"field_type": "Тип поля",
"when_to_write": "Коли записувати",
"salesforce_on_booking_write_to_record": "При бронюванні, записати в користувацьке поле запису {{record}} учасника",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Дата початку бронювання",
"booking_created_date": "Дата створення бронювання",
"booking_reassigned_to_host": "Бронювання перепризначено {{host}}",
"access_denied": "Доступ заборонено",
"salesforce_route_to_owner": "Власник контакту буде ведучим Round Robin, якщо доступний",
"salesforce_do_not_route_to_owner": "Власник контакту не буде примусово призначений (може бути ведучим, якщо відповідає атрибутам і критеріям Round Robin)",
"salesforce_route_to_custom_lookup_field": "Маршрутизація до користувача, який відповідає полю пошуку в обліковому записі",
"salesforce_option": "Опція Salesforce",
"lookup_field_name": "Назва поля пошуку",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+18 -5
View File
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "Thao tác cần làm để xếp lại lịch: Vui lòng đặt thời gian mới cho {{eventType}} với {{name}}",
"hi_user_name": "Xin chào {{name}}",
"ics_event_title": "{{eventType}} với {{name}}",
"please_book_a_time_sometime_later": "Rất tiếc, chúng tôi không thể kết nối bạn lần này. Vui lòng lên lịch cuộc gọi trong tương lai.",
"please_book_a_time_sometime_later": "Có vẻ như tất cả các chuyên gia của chúng tôi hiện đang bận. Vui lòng đặt lịch cuộc gọi vào thời gian phù hợp nhất với bạn và chúng tôi sẽ sẵn sàng hỗ trợ bạn.",
"schedule_instead": "Thay vào đó, hãy đặt lịch",
"new_event_subject": "Sự kiện mới: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "Tham gia bằng {{entryPoint}}",
"notes": "Ghi chú",
@@ -350,9 +351,13 @@
"other": "Khác",
"email_sign_in_subject": "Liên kết đăng nhập cho {{appName}}",
"round_robin_emailed_you_and_attendees": "Bạn sẽ gặp {{user}}. Chúng tôi đã gửi email với lời mời lịch và chi tiết cho tất cả mọi người.",
"round_robin_emailed_host_and_attendee": "{{host}} sẽ gặp {{attendee}}. Chúng tôi đã gửi email kèm lời mời lịch với đầy đủ thông tin chi tiết đến tất cả mọi người.",
"emailed_you_and_attendees": "Chúng tôi đã gửi email cho bạn và những người tham dự khác một lời mời theo lịch hẹn với tất cả các chi tiết đi kèm.",
"emailed_host_and_attendee": "Chúng tôi đã gửi email kèm lời mời lịch với đầy đủ thông tin chi tiết đến tất cả mọi người.",
"emailed_you_and_attendees_recurring": "Chúng tôi đã gửi email cho bạn và những người tham dự khác một lời mời theo lịch hẹn cho sự kiện định kỳ đầu tiên trong số những sự kiện định kỳ này.",
"round_robin_emailed_you_and_attendees_recurring": "Bạn sẽ gặp {{user}}. Chúng tôi đã gửi email với lời mời lịch và chi tiết cho tất cả mọi người cho sự kiện lặp lại đầu tiên này.",
"emailed_host_and_attendee_recurring": "Chúng tôi đã gửi email kèm lời mời lịch với đầy đủ thông tin chi tiết đến tất cả mọi người cho sự kiện đầu tiên trong chuỗi sự kiện định kỳ này.",
"round_robin_emailed_you_and_attendees_recurring": "Bạn sẽ gặp {{user}}. Chúng tôi đã gửi email kèm lời mời lịch với đầy đủ thông tin chi tiết đến tất cả mọi người cho sự kiện đầu tiên trong chuỗi sự kiện định kỳ này.",
"round_robin_emailed_host_and_attendee_recurring": "{{host}} sẽ gặp {{attendee}}. Chúng tôi đã gửi email kèm lời mời lịch với đầy đủ thông tin chi tiết đến tất cả mọi người cho sự kiện đầu tiên trong chuỗi sự kiện định kỳ này.",
"emailed_you_and_any_other_attendees": "Bạn và mọi người tham dự khác đã được gửi email với thông tin này.",
"needs_to_be_confirmed_or_rejected": "Đặt hẹn của bạn vẫn cần được xác nhận hoặc từ chối.",
"needs_to_be_confirmed_or_rejected_recurring": "Cuộc họp định kỳ của bạn vẫn cần được xác nhận hoặc từ chối.",
@@ -1242,8 +1247,8 @@
"number_provided": "Số điện thoại sẽ được cung ứng",
"before_event_trigger": "trước khi sự kiện bắt đầu",
"event_cancelled_trigger": "khi sự kiện bị huỷ",
"after_hosts_cal_video_no_show": "Sau khi người tổ chức không tham gia video trên Cal",
"after_guests_cal_video_no_show": "Sau khi khách mời không tham gia video trên Cal",
"after_hosts_cal_video_no_show": "Sau khi người chủ trì không tham gia cuộc gọi video",
"after_guests_cal_video_no_show": "Sau khi khách không tham gia cuộc gọi video",
"new_event_trigger": "khi sự kiện mới được đặt lịch hẹn",
"email_host_action": "gửi email đến chủ sự kiện",
"email_attendee_action": "gửi email đến người tham gia",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "Chọn một số thời gian trống và nhúng chúng vào trong Email của bạn",
"select_time": "Chọn thời gian",
"select_date": "Chọn ngày",
"connecting_you_to_someone": "Chúng tôi đang kết nối bạn với ai đó.",
"connecting_you_to_someone": "Chúng tôi đang kết nối bạn với một người từ {{orgName}}.",
"please_do_not_close_this_tab": "Vui lòng không đóng hoặc làm mới trang này",
"see_all_available_times": "Xem tất cả những thời gian trống",
"org_team_names_example_1": "ví dụ Nhóm Tiếp thị",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "Thời gian kết thúc sự kiện theo múi giờ của Người tham dự",
"salesforce_create_event_on_contact": "Tạo sự kiện trên liên hệ, nếu tồn tại. Nếu không, chuyển sang khách hàng tiềm năng",
"salesforce_owner_name_to_change": "Tên chủ sở hữu cần thay đổi",
"dont_have_access_this_page": "Bạn không có quyền truy cập trang này",
"you_need_admin_or_owner_privileges_to_access": "Để xem hoặc tương tác với trang này, bạn cần có quyền quản trị viên hoặc chủ sở hữu",
"field_type": "Loại trường",
"when_to_write": "Khi nào ghi",
"salesforce_on_booking_write_to_record": "Khi đặt lịch, ghi vào trường tùy chỉnh trên bản ghi {{record}} của người tham dự",
@@ -2753,5 +2760,11 @@
"booking_start_date": "Ngày bắt đầu đặt lịch",
"booking_created_date": "Ngày tạo đặt lịch",
"booking_reassigned_to_host": "Đặt lịch được chuyển giao cho {{host}}",
"access_denied": "Từ chối truy cập",
"salesforce_route_to_owner": "Người sở hữu liên hệ sẽ là người chủ trì Round Robin nếu khả dụng",
"salesforce_do_not_route_to_owner": "Người sở hữu liên hệ sẽ không bị bắt buộc (vẫn có thể là người chủ trì nếu phù hợp với các thuộc tính và tiêu chí Round Robin)",
"salesforce_route_to_custom_lookup_field": "Chuyển đến người dùng phù hợp với trường tra cứu trên tài khoản",
"salesforce_option": "Tùy chọn Salesforce",
"lookup_field_name": "Tên trường tra cứu",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "需要重新安排操作: 请为名称为 {{name}} 的 {{eventType}} 预约新的时间",
"hi_user_name": "您好 {{name}}",
"ics_event_title": "与 {{name}} 的 {{eventType}}",
"please_book_a_time_sometime_later": "Oops, 我们无法联系到您。请您另外安排一次计划会议。",
"please_book_a_time_sometime_later": "看起来我们所有的专家现在都很忙。请安排一个适合您的时间进行通话,我们将准备好为您提供帮助。",
"schedule_instead": "改为安排",
"new_event_subject": "新活动: {{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "由 {{entryPoint}} 加入",
"notes": "备注",
@@ -350,9 +351,13 @@
"other": "其他",
"email_sign_in_subject": "您的 {{appName}} 登录链接",
"round_robin_emailed_you_and_attendees": "您将与 {{user}} 会面。我们已向所有人发送了包含详细信息的日历邀请邮件。",
"round_robin_emailed_host_and_attendee": "{{host}}将与{{attendee}}会面。我们已向所有人发送了包含详细信息的日历邀请邮件。",
"emailed_you_and_attendees": "我们通过电子邮件给您和其他参与者发送了一份包含所有详细信息的日历邀请。",
"emailed_host_and_attendee": "我们已向所有人发送了包含详细信息的日历邀请邮件。",
"emailed_you_and_attendees_recurring": "我们通过电子邮件给您和其他参与者发送了第一次定期活动的日历邀请。",
"round_robin_emailed_you_and_attendees_recurring": "您将与 {{user}} 会面。我们已向所有人发送了包含详细信息的日历邀请邮件,适用于这些重复事件的第一次。",
"emailed_host_and_attendee_recurring": "我们已向所有人发送了首次循环会议的日历邀请邮件及详细信息。",
"round_robin_emailed_you_and_attendees_recurring": "您将与{{user}}会面。我们已向所有人发送了首次循环会议的日历邀请邮件及详细信息。",
"round_robin_emailed_host_and_attendee_recurring": "{{host}}将与{{attendee}}会面。我们已向所有人发送了首次循环会议的日历邀请邮件及详细信息。",
"emailed_you_and_any_other_attendees": "已向您和其他参与者发送了关于此信息的电子邮件",
"needs_to_be_confirmed_or_rejected": "您的预约仍然需要确认或拒绝。",
"needs_to_be_confirmed_or_rejected_recurring": "您的定期会议仍然需要确认或拒绝。",
@@ -1242,8 +1247,8 @@
"number_provided": "将提供电话号码",
"before_event_trigger": "活动开始前",
"event_cancelled_trigger": "活动取消后",
"after_hosts_cal_video_no_show": "主持人未加入 Cal 视频后的处理",
"after_guests_cal_video_no_show": "嘉宾未加入 Cal 视频后的处理",
"after_hosts_cal_video_no_show": "主持人未加入 Cal 视频后",
"after_guests_cal_video_no_show": "嘉宾未加入 Cal 视频后",
"new_event_trigger": "预约新活动时",
"email_host_action": "向主持人发送电子邮件",
"email_attendee_action": "向参与者发送电子邮件",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "选择几个可预约时间并将它们嵌入到您的电子邮件",
"select_time": "选择时间",
"select_date": "选择日期",
"connecting_you_to_someone": "我们正在为您创建连接",
"connecting_you_to_someone": "我们正在为您接通{{orgName}}的工作人员。",
"please_do_not_close_this_tab": "请不要关闭或刷新此页面",
"see_all_available_times": "查看所有可预约时间",
"org_team_names_example_1": "例如,营销团队",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "参与者时区的事件结束时间",
"salesforce_create_event_on_contact": "如果联系人存在,则在联系人上创建事件。否则回退到潜在客户",
"salesforce_owner_name_to_change": "要更改的所有者名称",
"dont_have_access_this_page": "您无权访问此页面",
"you_need_admin_or_owner_privileges_to_access": "要查看或操作此页面,您必须拥有管理员或所有者权限",
"field_type": "字段类型",
"when_to_write": "何时写入",
"salesforce_on_booking_write_to_record": "预约时,写入参与者 {{record}} 记录的自定义字段",
@@ -2753,5 +2760,11 @@
"booking_start_date": "预约开始日期",
"booking_created_date": "预约创建日期",
"booking_reassigned_to_host": "预约重新分配给 {{host}}",
"access_denied": "访问被拒绝",
"salesforce_route_to_owner": "如果联系人所有者可用,将作为轮询主持人",
"salesforce_do_not_route_to_owner": "不会强制指定联系人所有者(如果符合属性和轮询标准,仍可成为主持人)",
"salesforce_route_to_custom_lookup_field": "路由至与账户查找字段匹配的用户",
"salesforce_option": "Salesforce选项",
"lookup_field_name": "查找字段名称",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 在此上方添加您的新字符串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -139,7 +139,8 @@
"requested_to_reschedule_subject_attendee": "需進行重新預約操作:請為與 {{name}} 的 {{eventType}} 預訂新時間",
"hi_user_name": "哈囉 {{name}}",
"ics_event_title": "與 {{name}} 的 {{eventType}}",
"please_book_a_time_sometime_later": "抱歉,這次無法連接。請改為安排未來的通話。",
"please_book_a_time_sometime_later": "目前我們的專家都在忙碌中。請選擇一個最適合您的時間預約通話,我們將準備好為您提供協助。",
"schedule_instead": "立即預約",
"new_event_subject": "新活動:{{attendeeName}} - {{date}} - {{eventType}}",
"join_by_entrypoint": "透過 {{entryPoint}} 加入",
"notes": "備註",
@@ -350,9 +351,13 @@
"other": "其它",
"email_sign_in_subject": "您的「{{appName}}」登入連結",
"round_robin_emailed_you_and_attendees": "您將與 {{user}} 會面。我們已向所有人發送了包含詳細資訊的日曆邀請。",
"round_robin_emailed_host_and_attendee": "{{host}}將與{{attendee}}會面。我們已向所有人發送含有詳細資訊的行事曆邀請郵件。",
"emailed_you_and_attendees": "已經寄出行事曆邀請,包含其他與會者都會收到有全部細節的電子郵件。",
"emailed_host_and_attendee": "我們已向所有人發送含有詳細資訊的行事曆邀請郵件。",
"emailed_you_and_attendees_recurring": "已就這系列定期活動的首次活動,寄出行事曆邀請給您和其他與會者。",
"round_robin_emailed_you_and_attendees_recurring": "您將與 {{user}} 會面。我們已向所有人發送了包含詳細資訊的日曆邀請,這是這些重複事件中的第一次。",
"emailed_host_and_attendee_recurring": "我們已向所有人發送首次週期性會議的行事曆邀請郵件及詳細資訊。",
"round_robin_emailed_you_and_attendees_recurring": "您將與{{user}}會面。我們已向所有人發送首次週期性會議的行事曆邀請郵件及詳細資訊。",
"round_robin_emailed_host_and_attendee_recurring": "{{host}}將與{{attendee}}會面。我們已向所有人發送首次週期性會議的行事曆邀請郵件及詳細資訊。",
"emailed_you_and_any_other_attendees": "您與其他與會者已經收到這份資訊的電子郵件。",
"needs_to_be_confirmed_or_rejected": "此預約仍得經過確認,或遭到拒絕。",
"needs_to_be_confirmed_or_rejected_recurring": "您的定期會議仍需確認或拒絕。",
@@ -1242,8 +1247,8 @@
"number_provided": "將提供電話號碼",
"before_event_trigger": "活動開始前",
"event_cancelled_trigger": "活動取消時",
"after_hosts_cal_video_no_show": "主持人未加入 Cal 視訊後",
"after_guests_cal_video_no_show": "賓客未加入 Cal 視訊後",
"after_hosts_cal_video_no_show": "主持人未加入視訊會議後",
"after_guests_cal_video_no_show": "訪客未加入視訊會議後",
"new_event_trigger": "預約新活動時",
"email_host_action": "傳送電子郵件給主辦者",
"email_attendee_action": "傳送電子郵件給與會者",
@@ -2210,7 +2215,7 @@
"add_times_to_your_email": "選取幾個開放預約的時段,然後嵌入您的電子郵件",
"select_time": "選取時間",
"select_date": "選取日期",
"connecting_you_to_someone": "我們正在為您連接某人。",
"connecting_you_to_someone": "我們正在為您連接 {{orgName}} 的人員。",
"please_do_not_close_this_tab": "請勿關閉或重新整理此頁面",
"see_all_available_times": "查看所有可預約時段",
"org_team_names_example_1": "例如行銷團隊",
@@ -2745,6 +2750,8 @@
"event_end_time_in_attendee_timezone_info": "參與者時區的活動結束時間",
"salesforce_create_event_on_contact": "如果聯絡人存在,則在聯絡人上建立事件。否則回退到潛在客戶",
"salesforce_owner_name_to_change": "要更改的擁有者名稱",
"dont_have_access_this_page": "您無權存取此頁面",
"you_need_admin_or_owner_privileges_to_access": "若要查看或使用此頁面,您必須具有管理員或擁有者權限",
"field_type": "欄位類型",
"when_to_write": "何時寫入",
"salesforce_on_booking_write_to_record": "預約時,寫入參與者 {{record}} 記錄的自定義欄位",
@@ -2753,5 +2760,11 @@
"booking_start_date": "預約開始日期",
"booking_created_date": "預約創建日期",
"booking_reassigned_to_host": "預約重新分配給 {{host}}",
"access_denied": "拒絕存取",
"salesforce_route_to_owner": "如果聯絡人負責人可用,將成為Round Robin主持人",
"salesforce_do_not_route_to_owner": "不會強制指定聯絡人負責人(如果符合屬性和Round Robin條件,仍可成為主持人)",
"salesforce_route_to_custom_lookup_field": "路由至符合帳戶查詢欄位的使用者",
"salesforce_option": "Salesforce選項",
"lookup_field_name": "查詢欄位名稱",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 請在此處新增您的字串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
File diff suppressed because it is too large Load Diff
+18 -5
View File
@@ -141,7 +141,8 @@ checksums:
requested_to_reschedule_subject_attendee: 8c41aa43f412fd739407d9a1eaa82c15
hi_user_name: fc0d6128cf9a150638e635d2b2aa7397
ics_event_title: ad10ef33288a55748e6001607d528ff3
please_book_a_time_sometime_later: 89f131f8b3c7b4bc1a288a0ba052541c
please_book_a_time_sometime_later: 5353ec92d16f02eba6365819fddfc215
schedule_instead: d09667d846cefe86d8a1275a6624b310
new_event_subject: eea212a9fd5e66baf8b983b8bc9d7d63
join_by_entrypoint: 116d507f1b3a64cd2538e1073935173c
notes: 93c7ef9bc767f51fbe360afcf6b1fecb
@@ -352,9 +353,13 @@ checksums:
other: 79acaa6cd481262bea4e743a422529d2
email_sign_in_subject: d67308a3262ab416c083ca041b8690a1
round_robin_emailed_you_and_attendees: 74b9d35a245724c3d901ea28a3221484
round_robin_emailed_host_and_attendee: 32b8afb73c8d2622e80419dc5c91b483
emailed_you_and_attendees: e0f8269315964727ff509f17db78dec8
emailed_host_and_attendee: e0f8269315964727ff509f17db78dec8
emailed_you_and_attendees_recurring: ba5f9605b0e0f16d97cc1a4462c52924
round_robin_emailed_you_and_attendees_recurring: 7166cfe983fb8d1dfcb0e816e599fec2
emailed_host_and_attendee_recurring: ba5f9605b0e0f16d97cc1a4462c52924
round_robin_emailed_you_and_attendees_recurring: e38959c47e3f9cf24a8cd819c5fa2fbd
round_robin_emailed_host_and_attendee_recurring: 340b6e5ec29b7f478e1a08106c10a9b3
emailed_you_and_any_other_attendees: 91fdd4bf3fb673086ebcbda8d8983b32
needs_to_be_confirmed_or_rejected: 913a2d9efd305e965aac50a6687e47f8
needs_to_be_confirmed_or_rejected_recurring: 3f4cdc1672c21265f74da0481ff31972
@@ -1244,8 +1249,8 @@ checksums:
number_provided: 3486dd81e0aace30d7d39116a512dc77
before_event_trigger: 8f4c3aa39367d1e1d22d0380ba73591c
event_cancelled_trigger: b5d22f397e0f564fcf431032b75ff1af
after_hosts_cal_video_no_show: 6b190531cc1bd5f00a6d3a31188d277c
after_guests_cal_video_no_show: e5833aeb28ef1004fbeae2c91754d3e7
after_hosts_cal_video_no_show: 3ad095ab31649d79abbaf4fff4460bf5
after_guests_cal_video_no_show: edf9db3ae09d0d89406efb1656d31820
new_event_trigger: fbee38b5765412419941add7ff1e3fb9
email_host_action: 9566929caf21c96cedc11447e1de34ff
email_attendee_action: 3ca2ca348baef93742f3a1889ffcc96b
@@ -2212,7 +2217,7 @@ checksums:
add_times_to_your_email: 572a04f56df1ec2623ea7ee8c9c9c5bb
select_time: cb9cc2393ca45c6faea13fe4c9d4d6a5
select_date: 1e6063bfd25d982048726ff586df55dc
connecting_you_to_someone: 4fb9cd52b2caacf09de19b843407d1a9
connecting_you_to_someone: 23f139181e74b0afe63cc9493e1f41bd
please_do_not_close_this_tab: 0fc355011de61686ff1dd5606336a33a
see_all_available_times: 4213ac0595fa798d9c140e13ec5b1133
org_team_names_example_1: 6dcddcb08fbac91d1eee90340088b33c
@@ -2747,6 +2752,8 @@ checksums:
event_end_time_in_attendee_timezone_info: 82ffc6118c662094eb130b74a1e59627
salesforce_create_event_on_contact: 82fe69b4ba08b1cb9c6465dc18f968b5
salesforce_owner_name_to_change: 000522ab557b02cfe4a5d49787259ef9
dont_have_access_this_page: c2341fe363c89498d3d0deb64f3977b1
you_need_admin_or_owner_privileges_to_access: 7f032471f243015def700f16681274b2
field_type: 7444da76fa3572d47ea5b5d86c50f11f
when_to_write: 2dab9955e5743f1bf39ee5066c5c3e91
salesforce_on_booking_write_to_record: 43d786b0d3f592a6b1d75ec567f43c70
@@ -2755,4 +2762,10 @@ checksums:
booking_start_date: ef6f4addaa24a5c7dce41b4d91868ba6
booking_created_date: 902300aaa13a56a2295d561d46073eeb
booking_reassigned_to_host: 9eb99d1201d75ac0366daf0f09bc360a
access_denied: 589456a5c4103e29c44e9df16a4eaf82
salesforce_route_to_owner: 39a88a7afb1c1e8fb9215e27ae7a7033
salesforce_do_not_route_to_owner: bcae6e5615c17b809c2334a541f75e78
salesforce_route_to_custom_lookup_field: 672a24e4de55eb073559e94b9266da7d
salesforce_option: f09423b2785ee269db428163fc0a58d0
lookup_field_name: 8d81d557128a52661d1ed9e9aae0575c
ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS: 18323f2f3fabb169a7cb50ff62433850
@@ -19,11 +19,6 @@ export async function getAllCalendars(
allCalendars = [...allCalendars, ...(response.data.items ?? [])];
pageToken = response.data.nextPageToken;
logger.error("Google Calendar pagination failed in the middle", {
totalSoFar: allCalendars.length,
hasMorePages: !!pageToken,
});
} while (pageToken);
return allCalendars;
@@ -87,20 +87,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
id: formId,
...entityPrismaWhereClause({ userId: user.id }),
},
include: {
team: {
select: {
members: true,
},
},
},
});
if (!form) {
return res.status(404).json({ message: "Form not found or unauthorized" });
}
if (!canEditEntity(form, user.id)) {
if (!(await canEditEntity(form, user.id))) {
return res.status(404).json({ message: "Form not found or unauthorized" });
}
@@ -22,11 +22,6 @@ export async function isFormCreateEditAllowed({
select: {
userId: true,
teamId: true,
team: {
select: {
members: true,
},
},
},
});
@@ -37,5 +32,5 @@ export async function isFormCreateEditAllowed({
});
}
return canEditEntity(form, userId);
return await canEditEntity(form, userId);
}
@@ -367,7 +367,7 @@ export const formMutationHandler = async ({ ctx, input }: FormMutationHandlerOpt
});
}
if (!canEditEntity(sourceForm, userId)) {
if (!(await canEditEntity(sourceForm, userId))) {
throw new TRPCError({
code: "NOT_FOUND",
message: `Form to duplicate: ${duplicateFrom} not found or you are unauthorized`,
@@ -36,8 +36,9 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => {
],
include: {
team: {
include: {
members: true,
select: {
id: true,
name: true,
},
},
_count: {
@@ -54,15 +55,19 @@ export const formsHandler = async ({ ctx, input }: FormsHandlerOptions) => {
}),
});
const serializableForms = [];
for (let i = 0; i < forms.length; i++) {
const form = forms[i];
const hasWriteAccess = canEditEntity(form, user.id);
serializableForms.push({
form: await getSerializableForm({ form: forms[i] }),
readOnly: !hasWriteAccess,
});
}
const serializableForms = await Promise.all(
forms.map(async (form) => {
const [hasWriteAccess, serializedForm] = await Promise.all([
canEditEntity(form, user.id),
getSerializableForm({ form }),
]);
return {
form: serializedForm,
readOnly: !hasWriteAccess,
};
})
);
return {
filtered: serializableForms,
@@ -49,6 +49,7 @@ async function getResponseWithFormFieldsHandler({ ctx, input }: GetResponseWithF
},
team: {
select: {
id: true,
members: true,
slug: true,
parent: {
@@ -74,7 +75,7 @@ async function getResponseWithFormFieldsHandler({ ctx, input }: GetResponseWithF
// TODO: To make the check stricter, we could check if the user is admin/owner of the team or a member that is the organizer.
// But the exact criteria of showing a booking to the user could be trickier. Maybe we allow hosts as well to access the booking and thus should allow them as well to reroute
if (!canAccessEntity(form, user.id)) {
if (!(await canAccessEntity(form, user.id))) {
throw new TRPCError({
code: "FORBIDDEN",
message: translate("you_dont_have_access_to_reroute_this_booking"),
@@ -167,7 +167,8 @@ export async function onFormSubmission(
});
const promisesFormSubmittedNoEvent = webhooksFormSubmittedNoEvent.map((webhook) => {
const scheduledAt = dayjs().add(10, "minute").toDate();
const scheduledAt = dayjs().add(60, "minute").toDate();
return tasker.create(
"triggerFormSubmittedNoEventWebhook",
{
@@ -93,6 +93,20 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
value: "",
});
// Used when creating events under leads or contacts under account
const CreateContactUnderAccount = () => {
return (
<Switch
label={t("salesforce_create_new_contact_under_account")}
labelOnLeading
checked={createNewContactUnderAccount}
onCheckedChange={(checked) => {
setAppData("createNewContactUnderAccount", checked);
}}
/>
);
};
return (
<AppCard
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
@@ -142,19 +156,15 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
setAppData("createEventOnLeadCheckForContact", checked);
}}
/>
<div className="mt-4">
<CreateContactUnderAccount />
</div>
</div>
) : null}
{createEventOnSelectedOption.value === SalesforceRecordEnum.ACCOUNT ? (
<>
<div className="mb-4">
<Switch
label={t("salesforce_create_new_contact_under_account")}
labelOnLeading
checked={createNewContactUnderAccount}
onCheckedChange={(checked) => {
setAppData("createNewContactUnderAccount", checked);
}}
/>
<CreateContactUnderAccount />
</div>
<div>
<Switch
+116 -44
View File
@@ -42,6 +42,8 @@ type ContactRecord = {
[key: string]: any;
};
type Attendee = { email: string; name: string };
const salesforceTokenSchema = z.object({
id: z.string(),
issued_at: z.string(),
@@ -398,35 +400,56 @@ export default class SalesforceCRMService implements CRM {
: [];
}
async createContacts(contactsToCreate: { email: string; name: string }[], organizerEmail?: string) {
async createContacts(contactsToCreate: Attendee[], organizerEmail?: string) {
const conn = await this.conn;
const appOptions = this.getAppOptions();
const createEventOn = appOptions.createEventOn ?? SalesforceRecordEnum.CONTACT;
// See if the organizer exists in the CRM
const organizerId = organizerEmail ? await this.getSalesforceUserIdFromEmail(organizerEmail) : undefined;
const createdContacts: { id: string; email: string }[] = [];
if (createEventOn === SalesforceRecordEnum.CONTACT || createEventOn === SalesforceRecordEnum.LEAD) {
// See if the organizer exists in the CRM
if (createEventOn === SalesforceRecordEnum.CONTACT) {
await Promise.all(
contactsToCreate.map(async (attendee) => {
return await conn
.sobject(createEventOn)
.create(
this.generateCreateRecordBody({
attendee,
recordType: createEventOn,
organizerId,
})
)
.then((result) => {
if (result.success) {
createdContacts.push({ id: result.id, email: attendee.email });
}
});
return await this.createAttendeeRecord({
attendee,
recordType: SalesforceRecordEnum.CONTACT,
organizerId,
}).then((result) => {
createdContacts.push(...result);
});
})
);
}
if (createEventOn === SalesforceRecordEnum.LEAD) {
// Base this off of the first contact
const attendee = contactsToCreate[0];
if (appOptions.createNewContactUnderAccount) {
// Check for an account
const accountId = await this.getAccountIdBasedOnEmailDomainOfContacts(attendee.email);
if (accountId) {
const createdAccountContacts = await this.createNewContactUnderAnAccount({
attendee,
accountId,
organizerId,
});
if (createdContacts.length > 0) {
createdContacts.push(...createdAccountContacts);
}
}
}
await this.createAttendeeRecord({ attendee, recordType: SalesforceRecordEnum.LEAD, organizerId }).then(
(result) => {
createdContacts.push(...result);
}
);
}
if (createEventOn === SalesforceRecordEnum.ACCOUNT) {
if (!appOptions.createNewContactUnderAccount && !appOptions.createLeadIfAccountNull) {
this.setDoNotCreateEvent(true);
@@ -441,34 +464,16 @@ export default class SalesforceCRMService implements CRM {
let contactCreated = false;
if (accountId && appOptions.createNewContactUnderAccount) {
// First see if the contact already exists and connect it to the account
const userQuery = await conn.query(`SELECT Id, Email FROM Contact WHERE Email = '${attendee.email}'`);
if (userQuery.records.length) {
const contact = userQuery.records[0] as { Id: string; Email: string };
await conn.sobject(SalesforceRecordEnum.CONTACT).update({
// The first argument is the WHERE clause
Id: contact.Id,
AccountId: accountId,
});
return [{ id: contact.Id, email: contact.Email }];
}
const createdAccountContacts = await this.createNewContactUnderAnAccount({
attendee,
accountId,
organizerId,
});
await conn
.sobject(SalesforceRecordEnum.CONTACT)
.create({
...this.generateCreateRecordBody({
attendee,
recordType: SalesforceRecordEnum.CONTACT,
organizerId,
}),
AccountId: accountId,
})
.then((result) => {
if (result.success) {
createdContacts.push({ id: result.id, email: attendee.email });
contactCreated = true;
}
});
if (createdContacts.length > 0) {
createdContacts.push(...createdAccountContacts);
contactCreated = true;
}
}
if (!accountId && appOptions.createLeadIfAccountNull && !contactCreated) {
@@ -629,6 +634,42 @@ export default class SalesforceCRMService implements CRM {
return dominantAccountId;
}
private async createAttendeeRecord({
attendee,
recordType,
organizerId,
accountId,
}: {
attendee: Attendee;
recordType: SalesforceRecordEnum;
organizerId?: string;
accountId?: string;
}) {
const conn = await this.conn;
return await conn
.sobject(recordType)
.create({
...this.generateCreateRecordBody({
attendee,
recordType: recordType,
organizerId,
}),
AccountId: accountId,
})
.then((result) => {
if (result.success) {
return [{ id: result.id, email: attendee.email }];
} else {
return [];
}
})
.catch((error) => {
this.log.error(`Error creating Salesforce contact for ${attendee.email} with error ${error}`);
return [];
});
}
private generateCreateRecordBody({
attendee,
recordType,
@@ -864,6 +905,37 @@ export default class SalesforceCRMService implements CRM {
return query.records[0] as Record<string, any>;
}
private async createNewContactUnderAnAccount({
attendee,
accountId,
organizerId,
}: {
attendee: Attendee;
accountId: string;
organizerId?: string;
}) {
const conn = await this.conn;
// First see if the contact already exists and connect it to the account
const userQuery = await conn.query(`SELECT Id, Email FROM Contact WHERE Email = '${attendee.email}'`);
if (userQuery.records.length) {
const contact = userQuery.records[0] as { Id: string; Email: string };
await conn.sobject(SalesforceRecordEnum.CONTACT).update({
// The first argument is the WHERE clause
Id: contact.Id,
AccountId: accountId,
});
return [{ id: contact.Id, email: contact.Email }];
}
return await this.createAttendeeRecord({
attendee,
recordType: SalesforceRecordEnum.CONTACT,
accountId,
organizerId,
});
}
async findUserEmailFromLookupField(
attendeeEmail: string,
fieldName: string,
+1 -1
View File
@@ -11,7 +11,7 @@ const handler: AppDeclarativeHandler = {
handlerType: "add",
redirect: {
newTab: true,
url: "https://www.telli.so/en/caldotcom",
url: "https://www.telli.com/en/caldotcom",
},
createCredential: ({ appType, user, slug, teamId }) =>
createDefaultInstallation({ appType, user: user, slug, key: {}, teamId }),
+1 -1
View File
@@ -4,7 +4,7 @@
"slug": "telli",
"type": "telli_automation",
"logo": "icon-dark.svg",
"url": "https://www.telli.so/en/caldotcom",
"url": "https://www.telli.com/en/caldotcom",
"variant": "automation",
"categories": ["automation"],
"publisher": "telli technologies GmbH",
-2
View File
@@ -118,8 +118,6 @@ export default class EventManager {
app.credentials.map((creds) => ({ ...creds, appName: app.name }))
);
// This includes all calendar-related apps, traditional calendars such as Google Calendar
// (type google_calendar) and non-traditional calendars such as CRMs like Close.com
// (type closecom_other_calendar)
this.calendarCredentials = appCredentials
.filter(
// Backwards compatibility until CRM manager is implemented
@@ -1,3 +1,5 @@
import type { CalendarEvent, Person } from "@calcom/types/Calendar";
import { renderEmail } from "../";
import AttendeeScheduledEmail from "./attendee-scheduled-email";
@@ -11,13 +13,17 @@ export default class AttendeeDeclinedEmail extends AttendeeScheduledEmail {
title: this.calEvent.title,
date: this.getFormattedDate(),
})}`,
html: await renderEmail("AttendeeDeclinedEmail", {
calEvent: this.calEvent,
attendee: this.attendee,
}),
html: await this.getHtml(this.calEvent, this.attendee),
text: this.getTextBody(
this.calEvent.recurringEvent?.count ? "event_request_declined_recurring" : "event_request_declined"
),
};
}
protected async getHtml(calEvent: CalendarEvent, attendee: Person) {
return await renderEmail("AttendeeDeclinedEmail", {
calEvent,
attendee,
});
}
}
@@ -42,14 +42,18 @@ export default class AttendeeScheduledEmail extends BaseEmail {
from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`,
replyTo: [...this.calEvent.attendees.map(({ email }) => email), this.calEvent.organizer.email],
subject: `${this.calEvent.title}`,
html: await renderEmail("AttendeeScheduledEmail", {
calEvent: clonedCalEvent,
attendee: this.attendee,
}),
html: await this.getHtml(clonedCalEvent, this.attendee),
text: this.getTextBody(),
};
}
protected async getHtml(calEvent: CalendarEvent, attendee: Person) {
return await renderEmail("AttendeeScheduledEmail", {
calEvent,
attendee,
});
}
protected getTextBody(title = "", subtitle = "emailed_you_and_any_other_attendees"): string {
return `
${this.t(
@@ -12,18 +12,19 @@ import generateIcsFile from "../lib/generateIcsFile";
import { GenerateIcsRole } from "../lib/generateIcsFile";
import BaseEmail from "./_base-email";
type Reassigned = { name: string | null; email: string; reason?: string; byUser?: string };
export default class OrganizerScheduledEmail extends BaseEmail {
calEvent: CalendarEvent;
t: TFunction;
newSeat?: boolean;
teamMember?: Person;
reassigned?: { name: string | null; email: string; reason?: string; byUser?: string };
reassigned?: Reassigned;
constructor(input: {
calEvent: CalendarEvent;
newSeat?: boolean;
teamMember?: Person;
reassigned?: { name: string | null; email: string; reason?: string; byUser?: string };
reassigned?: Reassigned;
}) {
super();
this.name = "SEND_BOOKING_CONFIRMATION";
@@ -48,17 +49,33 @@ export default class OrganizerScheduledEmail extends BaseEmail {
to: toAddresses.join(","),
replyTo: [this.calEvent.organizer.email, ...this.calEvent.attendees.map(({ email }) => email)],
subject: `${this.newSeat ? `${this.t("new_attendee")}: ` : ""}${this.calEvent.title}`,
html: await renderEmail("OrganizerScheduledEmail", {
calEvent: clonedCalEvent,
attendee: this.calEvent.organizer,
teamMember: this.teamMember,
newSeat: this.newSeat,
reassigned: this.reassigned,
}),
html: await this.getHtml(
clonedCalEvent,
this.calEvent.organizer,
this.teamMember,
this.newSeat,
this.reassigned
),
text: this.getTextBody(),
};
}
protected async getHtml(
calEvent: CalendarEvent,
attendee: Person,
teamMember?: Person,
newSeat?: boolean,
reassigned?: Reassigned
) {
return await renderEmail("OrganizerScheduledEmail", {
calEvent,
attendee,
teamMember,
newSeat,
reassigned,
});
}
protected getTextBody(
title = "",
subtitle = "emailed_you_and_any_other_attendees",
@@ -11,8 +11,6 @@ import { getLocaleFromRequest } from "@calcom/lib/getLocaleFromRequest";
import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { usernameHandler, type RequestWithUsernameStatus } from "@calcom/lib/server/username";
import { createWebUser as syncServicesCreateWebUser } from "@calcom/lib/sync/SyncServiceManager";
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import { validateAndGetCorrectedUsernameAndEmail } from "@calcom/lib/validateUsername";
import { prisma } from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
@@ -172,8 +170,6 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
team,
});
closeComUpsertTeamUser(team, user, membership.role);
// Accept any child team invites for orgs.
if (team.parent) {
await joinAnyChildTeamOnOrgInvite({
@@ -210,8 +206,6 @@ async function handler(req: RequestWithUsernameStatus, res: NextApiResponse) {
language: await getLocaleFromRequest(req),
username: username || "",
});
// Sync Services
await syncServicesCreateWebUser(user);
}
if (checkoutSessionId) {
@@ -8,7 +8,6 @@ import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
import logger from "@calcom/lib/logger";
import { isUsernameReservedDueToMigration } from "@calcom/lib/server/username";
import slugify from "@calcom/lib/slugify";
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import { validateAndGetCorrectedUsernameAndEmail } from "@calcom/lib/validateUsername";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
@@ -118,8 +117,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
team,
});
closeComUpsertTeamUser(team, user, membership.role);
// Accept any child team invites for orgs.
if (team.parent) {
await joinAnyChildTeamOnOrgInvite({
+3 -2
View File
@@ -201,6 +201,7 @@ const BookerComponent = ({
onGoBack={() => {
onGoBackInstantMeeting();
}}
orgName={event.data?.entity?.name}
/>
)}
</>
@@ -275,7 +276,7 @@ const BookerComponent = ({
data-testid="booker-container"
className={classNames(
...getBookerSizeClassNames(layout, bookerState, hideEventTypeDetails),
`bg-default dark:bg-muted grid max-w-full items-start sm:transition-[width] sm:duration-300 sm:motion-reduce:transition-none md:flex-row dark:[color-scheme:dark]`,
`bg-default dark:bg-muted grid max-w-full items-start dark:[color-scheme:dark] sm:transition-[width] sm:duration-300 sm:motion-reduce:transition-none md:flex-row`,
// We remove border only when the content covers entire viewport. Because in embed, it can almost never be the case that it covers entire viewport, we show the border there
(layout === BookerLayouts.MONTH_VIEW || isEmbed) && "border-subtle rounded-md",
!isEmbed && "sm:transition-[width] sm:duration-300",
@@ -411,7 +412,7 @@ const BookerComponent = ({
layout === BookerLayouts.COLUMN_VIEW
}
className={classNames(
"border-subtle rtl:border-default flex h-full w-full flex-col overflow-x-auto px-5 py-3 pb-0 ltr:md:border-l rtl:border-r",
"border-subtle rtl:border-default flex h-full w-full flex-col overflow-x-auto px-5 py-3 pb-0 rtl:border-r ltr:md:border-l",
layout === BookerLayouts.MONTH_VIEW &&
"h-full overflow-hidden md:w-[var(--booker-timeslots-width)]",
layout !== BookerLayouts.MONTH_VIEW && "sticky top-0"
@@ -30,7 +30,7 @@ export const LargeCalendar = ({
const selectedEventDuration = useBookerStore((state) => state.selectedDuration);
const overlayEvents = useOverlayCalendarStore((state) => state.overlayBusyDates);
const displayOverlay =
getQueryParam("overlayCalendar") === "true" || localStorage.getItem("overlayCalendarSwitchDefault");
getQueryParam("overlayCalendar") === "true" || localStorage?.getItem("overlayCalendarSwitchDefault");
const eventDuration = selectedEventDuration || event?.data?.length || 30;
@@ -17,11 +17,13 @@ export const RedirectToInstantMeetingModal = ({
onGoBack,
expiryTime,
instantVideoMeetingUrl,
orgName,
}: {
bookingId: number;
onGoBack: () => void;
expiryTime?: Date;
instantVideoMeetingUrl?: string;
orgName?: string | null;
}) => {
const { t } = useLocale();
const [timeRemaining, setTimeRemaining] = useState(calculateTimeRemaining());
@@ -88,12 +90,12 @@ export const RedirectToInstantMeetingModal = ({
onGoBack();
}}
color="primary">
{t("go_back")}
{t("schedule_instead")}
</Button>
</div>
) : (
<div className="text-center">
<p className="font-medium">{t("connecting_you_to_someone")}</p>
<p className="font-medium">{t("connecting_you_to_someone", { orgName })}</p>
<p className="font-bold">{t("please_do_not_close_this_tab")}</p>
<p className="mt-2 font-medium">
{t("please_schedule_future_call", {
+1 -1
View File
@@ -153,5 +153,5 @@ export type CustomClassNames = {
availableTimeSlotsTimeFormatToggle?: string;
availableTimes?: string;
};
atomsWrapper: string;
atomsWrapper?: string;
};
@@ -64,7 +64,7 @@ const SlotItem = ({
const { t } = useLocale();
const overlayCalendarToggled =
getQueryParam("overlayCalendar") === "true" || localStorage.getItem("overlayCalendarSwitchDefault");
getQueryParam("overlayCalendar") === "true" || localStorage?.getItem("overlayCalendarSwitchDefault");
const [timeFormat, timezone] = useTimePreferences((state) => [state.timeFormat, state.timezone]);
const bookingData = useBookerStore((state) => state.bookingData);
const layout = useBookerStore((state) => state.layout);
@@ -8,9 +8,9 @@ import { v5 as uuidv5 } from "uuid";
import processExternalId from "@calcom/app-store/_utils/calendars/processExternalId";
import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata";
import {
getLocationValueForDB,
MeetLocationType,
OrganizerDefaultConferencingAppType,
getLocationValueForDB,
} from "@calcom/app-store/locations";
import { DailyLocationType } from "@calcom/app-store/locations";
import { getAppFromSlug } from "@calcom/app-store/utils";
@@ -60,7 +60,6 @@ import { safeStringify } from "@calcom/lib/safeStringify";
import { DistributionMethod, getLuckyUser } from "@calcom/lib/server/getLuckyUser";
import { getTranslation } from "@calcom/lib/server/i18n";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/SyncServiceManager";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import prisma from "@calcom/prisma";
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/prisma/enums";
@@ -91,11 +90,11 @@ import { handleAppsStatus } from "./handleNewBooking/handleAppsStatus";
import { loadAndValidateUsers } from "./handleNewBooking/loadAndValidateUsers";
import { scheduleNoShowTriggers } from "./handleNewBooking/scheduleNoShowTriggers";
import type {
Invitee,
IEventTypePaymentCredentialType,
IsFixedAwareUser,
BookingType,
Booking,
BookingType,
IEventTypePaymentCredentialType,
Invitee,
IsFixedAwareUser,
} from "./handleNewBooking/types";
import { validateBookingTimeIsNotOutOfBounds } from "./handleNewBooking/validateBookingTimeIsNotOutOfBounds";
import { validateEventLength } from "./handleNewBooking/validateEventLength";
@@ -962,14 +961,6 @@ async function handler(
originalRescheduledBooking,
});
// @NOTE: Add specific try catch for all subsequent async calls to avoid error
// Sync Services
await syncServicesUpdateWebUser(
await prisma.user.findFirst({
where: { id: userId },
select: { id: true, email: true, name: true, username: true, createdDate: true },
})
);
evt.uid = booking?.uid ?? null;
evt.oneTimePassword = booking?.oneTimePassword ?? null;
@@ -28,11 +28,18 @@ const usePostHogHook: () => PostHogHook = isPostHogEnabled
const usePostHog = () => {
const posthog = usePostHogHook();
const { data } = trpc.viewer.me.useQuery();
const { data: statsData } = trpc.viewer.myStats.useQuery(undefined, {
trpc: {
context: {
skipBatch: true,
},
},
});
const { hasPaidPlan } = useHasPaidPlan();
const { hasTeamPlan } = useHasTeamPlan();
const identify = async () => {
if (!data) return;
if (!data || !statsData) return;
posthog.identify(String(data.id), {
distinctId: String(data.id),
@@ -49,13 +56,13 @@ const usePostHog = () => {
has_team_plan: hasTeamPlan,
metadata: data?.metadata,
completed_onboarding: data?.completedOnboarding,
sum_of_bookings: data?.sumOfBookings,
sum_of_calendars: data?.sumOfCalendars,
sum_of_teams: data?.sumOfTeams,
sum_of_bookings: statsData?.sumOfBookings,
sum_of_calendars: statsData?.sumOfCalendars,
sum_of_teams: statsData?.sumOfTeams,
has_orgs_plan: !!data?.organizationId,
organization: data?.organization?.slug,
sum_of_event_types: data?.sumOfEventTypes,
sum_of_team_event_types: data?.sumOfTeamEventTypes,
sum_of_event_types: statsData?.sumOfEventTypes,
sum_of_team_event_types: statsData?.sumOfTeamEventTypes,
is_premium: data?.isPremium,
});
};
@@ -12,7 +12,7 @@ export default function PostHogPageView() {
// Track pageviews
if (pathname && posthog) {
let url = window.origin + pathname;
if (searchParams.toString()) {
if (searchParams?.toString()) {
url = `${url}?${searchParams.toString()}`;
}
posthog.capture("$pageview", {
@@ -26,11 +26,18 @@ const useIntercomHook = isInterComEnabled
export const useIntercom = () => {
const hookData = useIntercomHook();
const { data } = trpc.viewer.me.useQuery();
const { data: statsData } = trpc.viewer.myStats.useQuery(undefined, {
trpc: {
context: {
skipBatch: true,
},
},
});
const { hasPaidPlan } = useHasPaidPlan();
const { hasTeamPlan } = useHasTeamPlan();
const boot = async () => {
if (!data) return;
if (!data || !statsData) return;
let userHash;
const req = await fetch(`/api/intercom-hash`);
@@ -61,13 +68,13 @@ export const useIntercom = () => {
metadata: data?.metadata,
completed_onboarding: data.completedOnboarding,
is_logged_in: !!data,
sum_of_bookings: data?.sumOfBookings,
sum_of_calendars: data?.sumOfCalendars,
sum_of_teams: data?.sumOfTeams,
sum_of_bookings: statsData?.sumOfBookings,
sum_of_calendars: statsData?.sumOfCalendars,
sum_of_teams: statsData?.sumOfTeams,
has_orgs_plan: !!data?.organizationId,
organization: data?.organization?.slug,
sum_of_event_types: data?.sumOfEventTypes,
sum_of_team_event_types: data?.sumOfTeamEventTypes,
sum_of_event_types: statsData?.sumOfEventTypes,
sum_of_team_event_types: statsData?.sumOfTeamEventTypes,
is_premium: data?.isPremium,
},
});
@@ -104,13 +111,13 @@ export const useIntercom = () => {
metadata: data?.metadata,
completed_onboarding: data?.completedOnboarding,
is_logged_in: !!data,
sum_of_bookings: data?.sumOfBookings,
sum_of_calendars: data?.sumOfCalendars,
sum_of_teams: data?.sumOfTeams,
sum_of_bookings: statsData?.sumOfBookings,
sum_of_calendars: statsData?.sumOfCalendars,
sum_of_teams: statsData?.sumOfTeams,
has_orgs_plan: !!data?.organizationId,
organization: data?.organization?.slug,
sum_of_event_types: data?.sumOfEventTypes,
sum_of_team_event_types: data?.sumOfTeamEventTypes,
sum_of_event_types: statsData?.sumOfEventTypes,
sum_of_team_event_types: statsData?.sumOfTeamEventTypes,
is_premium: data?.isPremium,
},
});
@@ -122,13 +129,22 @@ export const useIntercom = () => {
export const useBootIntercom = () => {
const { boot } = useIntercom();
const { data: user } = trpc.viewer.me.useQuery();
const { data: statsData } = trpc.viewer.myStats.useQuery(undefined, {
trpc: {
context: {
skipBatch: true,
},
},
});
useEffect(() => {
// not using useMediaQuery as it toggles between true and false
const showIntercom = localStorage.getItem("showIntercom");
if (!isInterComEnabled || showIntercom === "false" || window.innerWidth <= 768 || !user) return;
if (!isInterComEnabled || showIntercom === "false" || window.innerWidth <= 768 || !user || !statsData)
return;
boot();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user]);
}, [user, statsData]);
};
export default useIntercom;
@@ -8,7 +8,6 @@ import stripe from "@calcom/features/ee/payments/server/stripe";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { HttpError } from "@calcom/lib/http-error";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
import { closeComUpdateTeam } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
@@ -66,9 +65,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
return res.status(statusCode).json({ message });
}
}
// Sync Services: Close.com
closeComUpdateTeam(prevTeam, team);
}
if (!metadata) {
+10
View File
@@ -216,6 +216,16 @@ const assertCanAccessBooking = async (bookingUid: string, userId?: number) => {
if (!booking)
throw new HttpError({ statusCode: 403, message: "You are not allowed to access this booking" });
const isUpcoming = new Date(booking.endTime) >= new Date();
const isOngoing = isUpcoming && new Date() >= new Date(booking.startTime);
const isBookingInPast = new Date(booking.endTime) < new Date();
if (!isBookingInPast && !isOngoing) {
throw new HttpError({
statusCode: 403,
message: "Cannot mark no-show before the meeting has started.",
});
}
};
export default handleMarkNoShow;
+8 -14
View File
@@ -4,13 +4,12 @@ import dynamic from "next/dynamic";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useRouter } from "next/navigation";
import { useState, useMemo } from "react";
import { useState } from "react";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
import { classNames } from "@calcom/lib";
import { IS_CALCOM, IS_VISUAL_REGRESSION_TESTING, ENABLE_PROFILE_SWITCHER } from "@calcom/lib/constants";
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
import { getBookerBaseUrlSync } from "@calcom/lib/getBookerUrl/client";
import { useCopy } from "@calcom/lib/hooks/useCopy";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useNotifications, ButtonState } from "@calcom/lib/hooks/useNotifications";
@@ -62,16 +61,11 @@ export function SideBarContainer({ bannersHeight, isPlatformUser = false }: Side
export function SideBar({ bannersHeight, user }: SideBarProps) {
const { fetchAndCopyToClipboard } = useCopy();
const { t, isLocaleReady } = useLocale();
const orgBranding = useOrgBranding();
const pathname = usePathname();
const isPlatformPages = pathname?.startsWith("/settings/platform");
const [isReferalLoading, setIsReferalLoading] = useState(false);
const publicPageUrl = useMemo(() => {
if (!user?.org?.id) return `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user?.username}`;
const publicPageUrl = orgBranding?.slug ? getOrgFullOrigin(orgBranding.slug) : "";
return publicPageUrl;
}, [orgBranding?.slug, user?.username, user?.org?.id]);
const publicPageUrl = `${getBookerBaseUrlSync(user?.org?.slug ?? null)}/${user?.username}`;
const sidebarStylingAttributes = {
maxHeight: `calc(100vh - ${bannersHeight}px)`,
@@ -140,17 +134,17 @@ export function SideBar({ bannersHeight, user }: SideBarProps) {
)}>
<div className="flex h-full flex-col justify-between py-3 lg:pt-4">
<header className="todesktop:-mt-3 todesktop:flex-col-reverse todesktop:[-webkit-app-region:drag] items-center justify-between md:hidden lg:flex">
{orgBranding ? (
{user?.org ? (
!ENABLE_PROFILE_SWITCHER ? (
<Link href="/settings/organizations/profile" className="w-full px-1.5">
<div className="flex items-center gap-2 font-medium">
<Avatar
alt={`${orgBranding.name} logo`}
imageSrc={getPlaceholderAvatar(orgBranding.logoUrl, orgBranding.name)}
alt={`${user.org.name} logo`}
imageSrc={getPlaceholderAvatar(user.org.logoUrl, user.org.name)}
size="xsm"
/>
<p className="text line-clamp-1 text-sm">
<span>{orgBranding.name}</span>
<span>{user.org.name}</span>
</p>
</div>
</Link>
@@ -186,7 +180,7 @@ export function SideBar({ bannersHeight, user }: SideBarProps) {
className="group-hover:text-emphasis text-subtle h-4 w-4 flex-shrink-0"
/>
</button>
{!!orgBranding && (
{!!user?.org && (
<div data-testid="user-dropdown-trigger" className="flex items-center">
<UserDropdown small />
</div>
@@ -33,6 +33,10 @@ export const ZTriggerFormSubmittedNoEventWebhookPayloadSchema = z.object({
id: z.string(),
name: z.string(),
teamId: z.number().nullable(),
fields: z
.array(z.object({ id: z.string(), label: z.string() }).passthrough())
.nullable()
.default([]),
}),
});
@@ -52,6 +56,49 @@ export async function triggerFormSubmittedNoEventWebhook(payload: string): Promi
return;
}
const sixtyMinutesAgo = new Date(Date.now() - 60 * 60 * 1000);
const recentResponses =
(await prisma.app_RoutingForms_FormResponse.findMany({
where: {
formId: form.id,
createdAt: {
gte: sixtyMinutesAgo,
lt: new Date(),
},
routedToBookingUid: {
not: null,
},
NOT: {
id: responseId,
},
},
})) ?? [];
const emailValue = Object.values(responses).find(
(response): response is { value: string; label: string } => {
const value =
typeof response === "object" && response && "value" in response ? response.value : response;
return typeof value === "string" && value.includes("@");
}
)?.value;
// Check for duplicate email in recent responses
const hasDuplicate =
emailValue &&
recentResponses.some((response) => {
return Object.values(response.response as Record<string, { value: string; label: string }>).some(
(field) => {
if (!response.response || typeof response.response !== "object") return false;
return typeof field.value === "string" && field.value.toLowerCase() === emailValue.toLowerCase();
}
);
});
if (hasDuplicate) {
return;
}
await sendGenericWebhookPayload({
secretKey: webhook.secret,
triggerEvent: "FORM_SUBMITTED_NO_EVENT",
@@ -111,6 +111,7 @@ export const prepareNoShowTrigger = async (
booking: Booking;
webhook: TWebhook;
hostsThatDidntJoinTheCall: Host[];
hostsThatJoinedTheCall: Host[];
numberOfHostsThatJoined: number;
didGuestJoinTheCall: boolean;
} | void> => {
@@ -148,9 +149,16 @@ export const prepareNoShowTrigger = async (
const hosts = getHosts(booking);
const allParticipants = meetingDetails.data.flatMap((meeting) => meeting.participants);
const hostsThatDidntJoinTheCall = hosts.filter(
(host) => !checkIfUserJoinedTheCall(host.id, allParticipants)
);
const hostsThatJoinedTheCall: Host[] = [];
const hostsThatDidntJoinTheCall: Host[] = [];
for (const host of hosts) {
if (checkIfUserJoinedTheCall(host.id, allParticipants)) {
hostsThatJoinedTheCall.push(host);
} else {
hostsThatDidntJoinTheCall.push(host);
}
}
const numberOfHostsThatJoined = hosts.length - hostsThatDidntJoinTheCall.length;
@@ -158,5 +166,12 @@ export const prepareNoShowTrigger = async (
(meeting) => meeting.max_participants < numberOfHostsThatJoined
);
return { hostsThatDidntJoinTheCall, booking, numberOfHostsThatJoined, webhook, didGuestJoinTheCall };
return {
hostsThatDidntJoinTheCall,
hostsThatJoinedTheCall,
booking,
numberOfHostsThatJoined,
webhook,
didGuestJoinTheCall,
};
};
@@ -1,12 +1,36 @@
import { prisma } from "@calcom/prisma";
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { calculateMaxStartTime, sendWebhookPayload, prepareNoShowTrigger } from "./common";
import { calculateMaxStartTime, sendWebhookPayload, prepareNoShowTrigger, log } from "./common";
import type { Host } from "./common";
const markAllGuestNoshowInBooking = async ({
bookingId,
hostsThatJoinedTheCall,
}: {
bookingId: number;
hostsThatJoinedTheCall: Host[];
}) => {
try {
const hostsThatJoinedTheCallEmails = hostsThatJoinedTheCall.map((h) => h.email);
await prisma.attendee.updateMany({
where: {
bookingId,
email: { notIn: hostsThatJoinedTheCallEmails },
},
data: { noShow: true },
});
} catch (err) {
log.error("Error marking guests as no show in booking", err);
}
};
export async function triggerGuestNoShow(payload: string): Promise<void> {
const result = await prepareNoShowTrigger(payload);
if (!result) return;
const { webhook, booking, didGuestJoinTheCall } = result;
const { webhook, booking, hostsThatJoinedTheCall, didGuestJoinTheCall } = result;
const maxStartTime = calculateMaxStartTime(booking.startTime, webhook.time, webhook.timeUnit);
@@ -17,5 +41,7 @@ export async function triggerGuestNoShow(payload: string): Promise<void> {
booking,
maxStartTime
);
await markAllGuestNoshowInBooking({ bookingId: booking.id, hostsThatJoinedTheCall });
}
}
@@ -1,5 +1,3 @@
import StickyBox from "react-sticky-box";
import classNames from "@calcom/lib/classNames";
import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
@@ -51,11 +49,9 @@ const TroubleshooterComponent = ({ month }: TroubleshooterProps) => {
<div className="bg-default dark:bg-muted sticky top-0 z-10 [grid-area:header]">
<TroubleshooterHeader extraDays={extraDays} isMobile={isMobile} />
</div>
<StickyBox key="meta" className={classNames("relative z-10")}>
<div className="ps-6">
<TroubleshooterSidebar />
</div>
</StickyBox>
<div className="sticky top-0 z-10 ps-6">
<TroubleshooterSidebar />
</div>
<div className="ml[-1px] border-subtle sticky top-0 [grid-area:main]">
<LargeCalendar extraDays={extraDays} />
@@ -9,19 +9,13 @@ import {
useReactTable,
type ColumnDef,
} from "@tanstack/react-table";
import type { ColumnMeta } from "@tanstack/react-table";
import { useSession } from "next-auth/react";
import { useQueryState, parseAsBoolean } from "nuqs";
import { useMemo, useReducer, useRef, useState } from "react";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import { WEBAPP_URL } from "@calcom/lib/constants";
import {
downloadAsCsv,
generateCsvRaw,
generateHeaderFromReactTable,
sanitizeValue,
} from "@calcom/lib/csvUtils";
import { downloadAsCsv, generateCsvRaw, generateHeaderFromReactTable } from "@calcom/lib/csvUtils";
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
@@ -36,8 +30,8 @@ import {
DataTableSelectionBar,
DataTablePagination,
showToast,
useFetchMoreOnBottomReached,
} from "@calcom/ui";
import { useFetchMoreOnBottomReached } from "@calcom/ui/data-table";
import { useGetUserAttributes } from "@calcom/web/components/settings/platform/hooks/useGetUserAttributes";
import { DeleteBulkUsers } from "./BulkActions/DeleteBulkUsers";
@@ -53,11 +47,6 @@ import { InviteMemberModal } from "./InviteMemberModal";
import { TableActions } from "./UserTableActions";
import type { UserTableState, UserTableAction, UserTableUser } from "./types";
type CustomColumnMeta<TData, TValue> = ColumnMeta<TData, TValue> & {
sticky?: boolean;
stickLeft?: number;
};
const initialState: UserTableState = {
changeMemberRole: {
showModal: false,
@@ -217,9 +206,10 @@ export function UserListTable() {
enableHiding: false,
enableSorting: false,
meta: {
sticky: true,
stickLeft: 0,
} as CustomColumnMeta<UserTableUser, unknown>,
sticky: {
position: "left",
},
},
header: ({ table }) => (
<Checkbox
checked={table.getIsAllPageRowsSelected()}
@@ -245,9 +235,8 @@ export function UserListTable() {
return `Members`;
},
meta: {
sticky: true,
stickyLeft: 24,
} as CustomColumnMeta<UserTableUser, unknown>,
sticky: { position: "left", gap: 24 },
},
cell: ({ row }) => {
const { username, email, avatarUrl } = row.original;
return (
@@ -349,6 +338,9 @@ export function UserListTable() {
{
id: "actions",
enableHiding: false,
meta: {
sticky: { position: "right" },
},
cell: ({ row }) => {
const user = row.original;
const permissionsRaw = permissions;

Some files were not shown because too many files have changed in this diff Show More