Make WYSIWYG editor reusable (#6293)

* make text editor reusable

* use dropdown component for block type

* remove ring when clicking on block type

* allow excluding items in toolbar

* refactor code

* make AddVariableDropdown reusable

* fixed missed translations

* fixes variable translation issue

* change missed translation variables

* make AddVariablesDropdown reusable

* reorder block types in dropdown

* remove not needed prop

* code clean up

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Carina Wollendorfer
2023-01-09 14:15:11 +00:00
committed by GitHub
co-authored by CarinaWolli kodiakhq[bot]
parent 112d504148
commit a0135cdc59
46 changed files with 415 additions and 420 deletions
@@ -1077,13 +1077,13 @@
"new_seat_subject": "حضور جديد {{name}} لـ {{eventType}} في {{date}}",
"new_seat_title": "شخص ما أضاف نفسه إلى حدث",
"variable": "متغير",
"event_name_workflow": "اسم الحدث",
"organizer_name_workflow": "المنظِّم",
"attendee_name_workflow": "الحاضر",
"event_date_workflow": "تاريخ الحدث",
"event_time_workflow": "وقت الحدث",
"location_workflow": "الموقع",
"additional_notes_workflow": "ملاحظات إضافية",
"event_name_variable": "اسم الحدث",
"organizer_name_variable": "المنظِّم",
"attendee_name_variable": "الحاضر",
"event_date_variable": "تاريخ الحدث",
"event_time_variable": "وقت الحدث",
"location_variable": "الموقع",
"additional_notes_variable": "ملاحظات إضافية",
"app_upgrade_description": "لاستخدام هذه الميزة، تحتاج إلى الترقية إلى حساب Pro.",
"invalid_number": "رقم الهاتف غير صالح",
"navigate": "تنقّل",
@@ -1387,7 +1387,7 @@
"team_url_taken": "عنوان URL هذا مأخوذ بالفعل",
"team_publish": "نشر فريق",
"number_sms_notifications": "رقم الهاتف (إشعارات الرسائل النصية)",
"attendee_email_workflow": "اسم الحاضر",
"attendee_email_variable": "اسم الحاضر",
"attendee_email_info": "البريد الإلكتروني للشخص الحجز",
"kbar_search_placeholder": "اكتب أمرًا أو بحثًا...",
"invalid_credential": "لا! يبدو أن الصلاحية انتهت أو تم إلغاؤها. يرجى إعادة التثبيت مرة أخرى.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Nový účastník {{name}} události {{eventType}} dne {{date}}",
"new_seat_title": "Někdo se přidal k události",
"variable": "Proměnná",
"event_name_workflow": "Název události",
"organizer_name_workflow": "Jméno organizátora",
"attendee_name_workflow": "Jméno účastníka",
"event_date_workflow": "Datum události",
"event_time_workflow": "Čas události",
"location_workflow": "Místo",
"additional_notes_workflow": "Doplňující poznámky",
"event_name_variable": "Název události",
"organizer_name_variable": "Jméno organizátora",
"attendee_name_variable": "Jméno účastníka",
"event_date_variable": "Datum události",
"event_time_variable": "Čas události",
"location_variable": "Místo",
"additional_notes_variable": "Doplňující poznámky",
"app_upgrade_description": "Pokud chcete použít tuto funkci, musíte provést aktualizaci na účet Pro.",
"invalid_number": "Neplatné telefonní číslo",
"navigate": "Navigace",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Tato adresa URL je už obsazená",
"team_publish": "Zveřejnit tým",
"number_sms_notifications": "Číslo telefonu (SMS oznámení)",
"attendee_email_workflow": "E-mail účastníka",
"attendee_email_variable": "E-mail účastníka",
"attendee_email_info": "E-mail osoby provádějící rezervaci",
"kbar_search_placeholder": "Zadejte příkaz nebo vyhledejte...",
"invalid_credential": "Ale ne! Zdá se, že platnost oprávnění vypršela nebo byla zrušena. Proveďte novou instalaci.",
@@ -1078,13 +1078,13 @@
"new_seat_subject": "Neuer Teilnehmer {{name}} beim {{eventType}} am {{date}}",
"new_seat_title": "Jemand hat sich zu einem Ereignis hinzugefügt",
"variable": "Variable",
"event_name_workflow": "Event Name",
"organizer_name_workflow": "Organisator",
"attendee_name_workflow": "Teilnehmer",
"event_date_workflow": "Event Datum",
"event_time_workflow": "Event Zeit",
"location_workflow": "Ort",
"additional_notes_workflow": "Zusätzliche Notizen",
"event_name_variable": "Event Name",
"organizer_name_variable": "Organisator",
"attendee_name_variable": "Teilnehmer",
"event_date_variable": "Event Datum",
"event_time_variable": "Event Zeit",
"location_variable": "Ort",
"additional_notes_variable": "Zusätzliche Notizen",
"app_upgrade_description": "Um diese Funktion nutzen zu können, müssen Sie ein Upgrade auf einen Pro-Account durchführen.",
"invalid_number": "Ungültige Telefonnummer",
"navigate": "Navigieren",
@@ -1388,7 +1388,7 @@
"team_url_taken": "Diese URL ist bereits vergeben",
"team_publish": "Team veröffentlichen",
"number_sms_notifications": "Telefonnummer (SMS-Benachrichtigungen)",
"attendee_email_workflow": "Teilnehmer E-Mail",
"attendee_email_variable": "Teilnehmer E-Mail",
"attendee_email_info": "Die E-Mail-Adresse der buchenden Person",
"kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie...",
"invalid_credential": "Oh nein! Es sieht so aus, als ob die Berechtigung abgelaufen ist oder entzogen wurden. Bitte erneut installieren.",
@@ -1084,13 +1084,13 @@
"new_seat_subject": "New Attendee {{name}} on {{eventType}} at {{date}}",
"new_seat_title": "Someone has added themselves to an event",
"variable": "Variable",
"event_name_workflow": "Event name",
"organizer_name_workflow": "Organizer",
"attendee_name_workflow": "Attendee",
"event_date_workflow": "Event date",
"event_time_workflow": "Event time",
"location_workflow": "Location",
"additional_notes_workflow": "Additional notes",
"event_name_variable": "Event name",
"organizer_name_variable": "Organizer",
"attendee_name_variable": "Attendee",
"event_date_variable": "Event date",
"event_time_variable": "Event time",
"location_variable": "Location",
"additional_notes_variable": "Additional notes",
"app_upgrade_description": "In order to use this feature, you need to upgrade to a Pro account.",
"invalid_number": "Invalid phone number",
"navigate": "Navigate",
@@ -1404,7 +1404,7 @@
"team_url_taken": "This URL is already taken",
"team_publish": "Publish team",
"number_sms_notifications": "Phone number (SMS\u00a0notifications)",
"attendee_email_workflow": "Attendee email",
"attendee_email_variable": "Attendee email",
"attendee_email_info": "The person booking's email",
"kbar_search_placeholder": "Type a command or search...",
"invalid_credential": "Oh no! Looks like permission expired or was revoked. Please reinstall again.",
@@ -1459,7 +1459,7 @@
"individual":"Individual",
"all_bookings_filter_label":"All Bookings",
"all_users_filter_label":"All Users",
"meeting_url_workflow": "Meeting url",
"meeting_url_variable": "Meeting url",
"meeting_url_info": "The event meeting conference url",
"date_overrides": "Date overrides",
"date_overrides_subtitle": "Add dates when your availability changes from your daily hours.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Nuevo asistente {{name}} en {{eventType}} el {{date}}",
"new_seat_title": "Alguien se ha añadido a un evento",
"variable": "Variable",
"event_name_workflow": "Nombre del evento",
"organizer_name_workflow": "Nombre del organizador",
"attendee_name_workflow": "Nombre del asistente",
"event_date_workflow": "Fecha del evento",
"event_time_workflow": "Hora del evento",
"location_workflow": "Lugar",
"additional_notes_workflow": "Notas Adicionales",
"event_name_variable": "Nombre del evento",
"organizer_name_variable": "Nombre del organizador",
"attendee_name_variable": "Nombre del asistente",
"event_date_variable": "Fecha del evento",
"event_time_variable": "Hora del evento",
"location_variable": "Lugar",
"additional_notes_variable": "Notas Adicionales",
"app_upgrade_description": "Para poder usar esta función, necesita actualizarse a una cuenta Pro.",
"invalid_number": "Número de teléfono no válido",
"navigate": "Navegar",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Esta URL ya está en uso",
"team_publish": "Publicar equipo",
"number_sms_notifications": "Número de teléfono (notificaciones por SMS)",
"attendee_email_workflow": "Correo electrónico del asistente",
"attendee_email_variable": "Correo electrónico del asistente",
"attendee_email_info": "El correo electrónico de la persona que reserva",
"kbar_search_placeholder": "Escriba un comando o búsqueda...",
"invalid_credential": "¡Oh no! Parece que el permiso ha caducado o se ha revocado. Vuelva a instalarlo.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Nouveau participant {{name}} pour {{eventType}} le {{date}}",
"new_seat_title": "Un participant s'est ajouté à un événement",
"variable": "Variable",
"event_name_workflow": "Nom de l'événement",
"organizer_name_workflow": "Nom de l'organisateur",
"attendee_name_workflow": "Nom du participant",
"event_date_workflow": "Date de l'événement",
"event_time_workflow": "Heure de l'événement",
"location_workflow": "Localisation",
"additional_notes_workflow": "Notes additionnelles",
"event_name_variable": "Nom de l'événement",
"organizer_name_variable": "Nom de l'organisateur",
"attendee_name_variable": "Nom du participant",
"event_date_variable": "Date de l'événement",
"event_time_variable": "Heure de l'événement",
"location_variable": "Localisation",
"additional_notes_variable": "Notes additionnelles",
"app_upgrade_description": "Pour pouvoir utiliser cette fonctionnalité, vous devez passer à un compte Pro.",
"invalid_number": "Numéro de téléphone non valide",
"navigate": "Naviguer",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Cette URL est déjà prise",
"team_publish": "Publier l'équipe",
"number_sms_notifications": "Numéro de téléphone (notifications SMS)",
"attendee_email_workflow": "E-mail du participant",
"attendee_email_variable": "E-mail du participant",
"attendee_email_info": "E-mail de la personne ayant réservé",
"kbar_search_placeholder": "Saisissez une commande ou une recherche...",
"invalid_credential": "Oh non ! L'autorisation semble avoir expiré ou avoir été révoquée. Veuillez la réinstaller.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "משתתף/ת חדש/ה {{name}} ב{{eventType}} בתאריך {{date}}",
"new_seat_title": "מישהו הוסיף את עצמו לאירוע",
"variable": "משתנה",
"event_name_workflow": "שם האירוע",
"organizer_name_workflow": "שם המארגן/ת",
"attendee_name_workflow": "שם המשתתף/ת",
"event_date_workflow": "תאריך האירוע",
"event_time_workflow": "שעת האירוע",
"location_workflow": "מיקום",
"additional_notes_workflow": "הערות נוספות",
"event_name_variable": "שם האירוע",
"organizer_name_variable": "שם המארגן/ת",
"attendee_name_variable": "שם המשתתף/ת",
"event_date_variable": "תאריך האירוע",
"event_time_variable": "שעת האירוע",
"location_variable": "מיקום",
"additional_notes_variable": "הערות נוספות",
"app_upgrade_description": "כדי להשתמש בתכונה זו, עליך לשדרג לחשבון Pro.",
"invalid_number": "מספר טלפון לא תקין",
"navigate": "ניווט",
@@ -1386,7 +1386,7 @@
"team_url_taken": "כתובת ה-URL הזו כבר תפוסה",
"team_publish": "פרסום צוות",
"number_sms_notifications": "מספר טלפון (הודעות SMS)",
"attendee_email_workflow": "כתובת הדוא\"ל של המשתתף/ת",
"attendee_email_variable": "כתובת הדוא\"ל של המשתתף/ת",
"attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה",
"kbar_search_placeholder": "הקלד/י פקודה או חפש/י...",
"invalid_credential": "נראה שתוקף ההרשאה פג או שההרשאה בוטלה. יש להתקין מחדש שוב.",
@@ -212,9 +212,9 @@
"remove_app": "Alkalmazás eltávolítása",
"yes_remove_app": "Igen, távolítsd el az alkalmazást",
"web_conference": "Online konferencia",
"organizer_name_workflow": "Szervező",
"location_workflow": "Helyszín",
"additional_notes_workflow": "Egyéb jegyzetek",
"organizer_name_variable": "Szervező",
"location_variable": "Helyszín",
"additional_notes_variable": "Egyéb jegyzetek",
"organizer_name_info": "Neved",
"theme_light": "Világos",
"theme_dark": "Sötét"
@@ -1077,13 +1077,13 @@
"new_seat_subject": "Nuovo partecipante {{name}} a {{eventType}} il {{date}}",
"new_seat_title": "Qualcuno ha aggiunto se stesso a un evento",
"variable": "Variabile",
"event_name_workflow": "Nome evento",
"organizer_name_workflow": "Organizzatore",
"attendee_name_workflow": "Partecipante",
"event_date_workflow": "Data evento",
"event_time_workflow": "Ora evento",
"location_workflow": "Luogo",
"additional_notes_workflow": "Note aggiuntive",
"event_name_variable": "Nome evento",
"organizer_name_variable": "Organizzatore",
"attendee_name_variable": "Partecipante",
"event_date_variable": "Data evento",
"event_time_variable": "Ora evento",
"location_variable": "Luogo",
"additional_notes_variable": "Note aggiuntive",
"app_upgrade_description": "Per poter utilizzare questa funzionalità, è necessario passare a un account Pro.",
"invalid_number": "Numero di telefono non valido",
"navigate": "Esplora",
@@ -1387,7 +1387,7 @@
"team_url_taken": "URL già occupato",
"team_publish": "Pubblica team",
"number_sms_notifications": "Numero di telefono (notifiche SMS)",
"attendee_email_workflow": "E-mail partecipante",
"attendee_email_variable": "E-mail partecipante",
"attendee_email_info": "E-mail della persona che prenota",
"kbar_search_placeholder": "Digitare un comando o eseguire una ricerca...",
"invalid_credential": "Errore! Sembra che l'autorizzazione sia scaduta o che sia stata revocata. Prova a reinstallare.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "{{date}} の {{eventType}} への新規参加者 {{name}}",
"new_seat_title": "別のユーザーがイベントに自身を追加しました",
"variable": "変数",
"event_name_workflow": "イベントの名前",
"organizer_name_workflow": "主催者の名前",
"attendee_name_workflow": "出席者の名前",
"event_date_workflow": "イベントの日付",
"event_time_workflow": "イベントの時間",
"location_workflow": "場所",
"additional_notes_workflow": "備考",
"event_name_variable": "イベントの名前",
"organizer_name_variable": "主催者の名前",
"attendee_name_variable": "出席者の名前",
"event_date_variable": "イベントの日付",
"event_time_variable": "イベントの時間",
"location_variable": "場所",
"additional_notes_variable": "備考",
"app_upgrade_description": "この機能を利用するには、Pro アカウントへのアップグレードが必要です。",
"invalid_number": "電話番号が無効です",
"navigate": "ナビゲート",
@@ -1386,7 +1386,7 @@
"team_url_taken": "この URL は既に使用されています",
"team_publish": "チームを公開",
"number_sms_notifications": "電話番号(SMS 通知)",
"attendee_email_workflow": "出席者のメールアドレス",
"attendee_email_variable": "出席者のメールアドレス",
"attendee_email_info": "予約者のメールアドレス",
"kbar_search_placeholder": "コマンドを入力するか、検索...",
"invalid_credential": "アクセス許可の有効期限が切れたか、取り消されたようです。もう一度インストールしてください。",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "신규 참석자 {{name}}님이 {{date}}, {{eventType}}에 참석",
"new_seat_title": "누군가가 이벤트에 자신을 추가했습니다",
"variable": "변수",
"event_name_workflow": "이벤트 이름",
"organizer_name_workflow": "주최자",
"attendee_name_workflow": "참석자",
"event_date_workflow": "이벤트 날짜",
"event_time_workflow": "이벤트 시간",
"location_workflow": "위치",
"additional_notes_workflow": "추가 참고 사항",
"event_name_variable": "이벤트 이름",
"organizer_name_variable": "주최자",
"attendee_name_variable": "참석자",
"event_date_variable": "이벤트 날짜",
"event_time_variable": "이벤트 시간",
"location_variable": "위치",
"additional_notes_variable": "추가 참고 사항",
"app_upgrade_description": "이 기능을 사용하려면 Pro 계정으로 업그레이드해야 합니다.",
"invalid_number": "유효하지 않은 전화 번호",
"navigate": "탐색하기",
@@ -1387,7 +1387,7 @@
"team_url_taken": "이미 사용 중인 URL입니다",
"team_publish": "팀 게시",
"number_sms_notifications": "전화번호 (SMS notifications)",
"attendee_email_workflow": "참석자 이메일",
"attendee_email_variable": "참석자 이메일",
"attendee_email_info": "예약자 이메일",
"kbar_search_placeholder": "명령어를 입력하거나 검색하세요...",
"invalid_credential": "죄송합니다! 권한이 만료되었거나 취소된 것 같습니다. 다시 설치하십시오.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Nieuwe deelnemer {{name}} op {{eventType}} om {{date}}",
"new_seat_title": "Iemand heeft zichzelf toegevoegd aan een evenement",
"variable": "Variabel",
"event_name_workflow": "Naam gebeurtenis",
"organizer_name_workflow": "Naam organisator",
"attendee_name_workflow": "Deelnemer",
"event_date_workflow": "Datum gebeurtenis",
"event_time_workflow": "Tijd gebeurtenis",
"location_workflow": "Locatie",
"additional_notes_workflow": "Aanvullende opmerkingen",
"event_name_variable": "Naam gebeurtenis",
"organizer_name_variable": "Naam organisator",
"attendee_name_variable": "Deelnemer",
"event_date_variable": "Datum gebeurtenis",
"event_time_variable": "Tijd gebeurtenis",
"location_variable": "Locatie",
"additional_notes_variable": "Aanvullende opmerkingen",
"app_upgrade_description": "Om deze functie te gebruiken, moet u upgraden naar een Pro-account.",
"invalid_number": "Ongeldig telefoonnummer",
"navigate": "Navigeren",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Deze URL is al in gebruik",
"team_publish": "Team publiceren",
"number_sms_notifications": "Telefoonnummer (sms-meldingen)",
"attendee_email_workflow": "E-mailadres deelnemer",
"attendee_email_variable": "E-mailadres deelnemer",
"attendee_email_info": "Het e-mailadres van de persoon die boekt",
"kbar_search_placeholder": "Typ een opdracht of zoek...",
"invalid_credential": "Oh nee! Het lijkt erop dat de machtiging is verlopen of is ingetrokken. Installeer het opnieuw.",
@@ -1080,13 +1080,13 @@
"new_seat_subject": "Ny Deltaker {{name}} på {{eventType}} kl. {{date}}",
"new_seat_title": "Noen har lagt seg til en hendelse",
"variable": "Variabel",
"event_name_workflow": "Hendelsesnavn",
"organizer_name_workflow": "Arrangør",
"attendee_name_workflow": "Deltaker",
"event_date_workflow": "Hendelsesdato",
"event_time_workflow": "Tidspunkt for hendelse",
"location_workflow": "Sted",
"additional_notes_workflow": "Tilleggsinformasjon",
"event_name_variable": "Hendelsesnavn",
"organizer_name_variable": "Arrangør",
"attendee_name_variable": "Deltaker",
"event_date_variable": "Hendelsesdato",
"event_time_variable": "Tidspunkt for hendelse",
"location_variable": "Sted",
"additional_notes_variable": "Tilleggsinformasjon",
"app_upgrade_description": "For å bruke denne funksjonen må du oppgradere til en Pro-konto.",
"invalid_number": "Ugyldig telefonnummer",
"navigate": "Naviger",
@@ -1400,7 +1400,7 @@
"team_url_taken": "Denne URL'en er allerede tatt",
"team_publish": "Publiser team",
"number_sms_notifications": "Telefonnummer (SMS varsler)",
"attendee_email_workflow": "Deltakerens e-post",
"attendee_email_variable": "Deltakerens e-post",
"attendee_email_info": "Den som booker sin e-post",
"kbar_search_placeholder": "Skriv inn en kommando eller søk...",
"invalid_credential": "Å nei! Det ser ut til at tillatelsen er utløpt eller tilbakekalt. Vennligst installer på nytt.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Nowy uczestnik ({{name}}) wydarzenia {{eventType}} odbywającego się {{date}}",
"new_seat_title": "Ktoś dodał się do wydarzenia",
"variable": "Zmienna",
"event_name_workflow": "Nazwa wydarzenia",
"organizer_name_workflow": "Organizator",
"attendee_name_workflow": "Uczestnik",
"event_date_workflow": "Data wydarzenia",
"event_time_workflow": "Godzina wydarzenia",
"location_workflow": "Lokalizacja",
"additional_notes_workflow": "Dodatkowe uwagi",
"event_name_variable": "Nazwa wydarzenia",
"organizer_name_variable": "Organizator",
"attendee_name_variable": "Uczestnik",
"event_date_variable": "Data wydarzenia",
"event_time_variable": "Godzina wydarzenia",
"location_variable": "Lokalizacja",
"additional_notes_variable": "Dodatkowe uwagi",
"app_upgrade_description": "Aby korzystać z tej funkcji, musisz uaktualnić do konta Pro.",
"invalid_number": "Nieprawidłowy numer telefonu",
"navigate": "Nawigacja",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Ten adres URL jest już zajęty",
"team_publish": "Opublikuj zespół",
"number_sms_notifications": "Numer telefonu (powiadomienia SMS)",
"attendee_email_workflow": "Adres e-mail uczestnika",
"attendee_email_variable": "Adres e-mail uczestnika",
"attendee_email_info": "Adres e-mail osoby rezerwującej",
"kbar_search_placeholder": "Wpisz polecenie lub wyszukaj...",
"invalid_credential": "O nie! Wygląda na to, że uprawnienia wygasły lub zostały cofnięte. Zainstaluj aplikację ponownie.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Novo participante {{name}} no {{eventType}} em {{date}}",
"new_seat_title": "Alguém se adicionou a um evento",
"variable": "Variável",
"event_name_workflow": "Nome do evento",
"organizer_name_workflow": "Nome do organizador",
"attendee_name_workflow": "Nome do participante",
"event_date_workflow": "Data do evento",
"event_time_workflow": "Horário do evento",
"location_workflow": "Local",
"additional_notes_workflow": "Observações adicionais",
"event_name_variable": "Nome do evento",
"organizer_name_variable": "Nome do organizador",
"attendee_name_variable": "Nome do participante",
"event_date_variable": "Data do evento",
"event_time_variable": "Horário do evento",
"location_variable": "Local",
"additional_notes_variable": "Observações adicionais",
"app_upgrade_description": "Para usar este recurso, atualize para uma conta Pro.",
"invalid_number": "Número de telefone inválido",
"navigate": "Navegar",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Este URL já está em uso",
"team_publish": "Publicar equipe",
"number_sms_notifications": "Número de telefone (notificações de SMS)",
"attendee_email_workflow": "E-mail do participante",
"attendee_email_variable": "E-mail do participante",
"attendee_email_info": "O e-mail da pessoa que fez a reserva",
"kbar_search_placeholder": "Digite um comando ou procure...",
"invalid_credential": "Ah, não! Parece que a permissão expirou ou foi revogada. Reinstale novamente.",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "Novo participante {{name}} em {{eventType}} em {{date}}",
"new_seat_title": "Alguém se adicionou a um evento",
"variable": "Variável",
"event_name_workflow": "Nome do evento",
"organizer_name_workflow": "Organizador",
"attendee_name_workflow": "Participante",
"event_date_workflow": "Data do evento",
"event_time_workflow": "Hora do evento",
"location_workflow": "Localização",
"additional_notes_workflow": "Notas Adicionais",
"event_name_variable": "Nome do evento",
"organizer_name_variable": "Organizador",
"attendee_name_variable": "Participante",
"event_date_variable": "Data do evento",
"event_time_variable": "Hora do evento",
"location_variable": "Localização",
"additional_notes_variable": "Notas Adicionais",
"app_upgrade_description": "Para usar esta funcionalidade, tem de actualizar para uma conta Pro.",
"invalid_number": "Número de telefone inválido",
"navigate": "Navegar",
@@ -1387,7 +1387,7 @@
"team_url_taken": "Este endereço já está a ser utilizado",
"team_publish": "Publicar equipa",
"number_sms_notifications": "Número de telefone (notificações SMS)",
"attendee_email_workflow": "E-mail do participante",
"attendee_email_variable": "E-mail do participante",
"attendee_email_info": "O e-mail do responsável pela reserva",
"kbar_search_placeholder": "Digite um comando ou pesquise...",
"invalid_credential": "Oh não! Parece que a permissão expirou ou foi revogada. Por favor, reinstale novamente.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Participant nou, {{name}}, la {{eventType}} de pe {{date}}",
"new_seat_title": "Cineva s-a adăugat pe sine la un eveniment",
"variable": "Variabilă",
"event_name_workflow": "Denumire eveniment",
"organizer_name_workflow": "Organizator",
"attendee_name_workflow": "Participant",
"event_date_workflow": "Dată eveniment",
"event_time_workflow": "Oră eveniment",
"location_workflow": "Loc",
"additional_notes_workflow": "Note suplimentare",
"event_name_variable": "Denumire eveniment",
"organizer_name_variable": "Organizator",
"attendee_name_variable": "Participant",
"event_date_variable": "Dată eveniment",
"event_time_variable": "Oră eveniment",
"location_variable": "Loc",
"additional_notes_variable": "Note suplimentare",
"app_upgrade_description": "Pentru a utiliza această caracteristică, trebuie să faceți upgrade la un cont Pro.",
"invalid_number": "Număr de telefon nevalid",
"navigate": "Navigare",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Acest URL este folosit deja",
"team_publish": "Publicați echipa",
"number_sms_notifications": "Număr de telefon (notificări SMS)",
"attendee_email_workflow": "E-mail participant",
"attendee_email_variable": "E-mail participant",
"attendee_email_info": "E-mailul persoanei care efectuează rezervarea",
"kbar_search_placeholder": "Scrie o comandă sau caută...",
"invalid_credential": "Vai, nu! Se pare că permisiunea a expirat sau a fost revocată. Reinstalați din nou.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "{{eventType}}, {{date}}: новый участник {{name}}",
"new_seat_title": "Кто-то добавился к событию",
"variable": "Переменная",
"event_name_workflow": "Название события",
"organizer_name_workflow": "Организатор",
"attendee_name_workflow": "Участник",
"event_date_workflow": "Дата события",
"event_time_workflow": "Время события",
"location_workflow": "Местоположение",
"additional_notes_workflow": "Дополнительная информация",
"event_name_variable": "Название события",
"organizer_name_variable": "Организатор",
"attendee_name_variable": "Участник",
"event_date_variable": "Дата события",
"event_time_variable": "Время события",
"location_variable": "Местоположение",
"additional_notes_variable": "Дополнительная информация",
"app_upgrade_description": "Чтобы использовать эту функцию, необходимо перейти на аккаунт Pro.",
"invalid_number": "Неверный номер телефона",
"navigate": "Перейти",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Этот URL-адрес уже занят",
"team_publish": "Опубликовать команду",
"number_sms_notifications": "Номер телефона (SMS-уведомления)",
"attendee_email_workflow": "Электронная почта участника",
"attendee_email_variable": "Электронная почта участника",
"attendee_email_info": "Электронная почта участника, на которого оформляется бронирование",
"kbar_search_placeholder": "Введите команду или начните поиск...",
"invalid_credential": "Похоже, разрешение истекло или было отозвано. Необходима переустановка.",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "Novi učesnik {{name}} na {{eventType}} dana {{date}}",
"new_seat_title": "Neko se dodao na događaj",
"variable": "Promenljiva",
"event_name_workflow": "Naziv događaja",
"organizer_name_workflow": "Organizator",
"attendee_name_workflow": "Učesnik",
"event_date_workflow": "Datum događaja",
"event_time_workflow": "Vreme događaja",
"location_workflow": "Lokacija",
"additional_notes_workflow": "Dodatne beleške",
"event_name_variable": "Naziv događaja",
"organizer_name_variable": "Organizator",
"attendee_name_variable": "Učesnik",
"event_date_variable": "Datum događaja",
"event_time_variable": "Vreme događaja",
"location_variable": "Lokacija",
"additional_notes_variable": "Dodatne beleške",
"app_upgrade_description": "Da biste koristili ovu funkciju, morate izvršiti nadogradnju na Pro nalog.",
"invalid_number": "Neispravan broj telefona",
"navigate": "Navigacija",
@@ -1387,7 +1387,7 @@
"team_url_taken": "Ovaj URL je zauzet",
"team_publish": "Objavite tim",
"number_sms_notifications": "Broj telefona (obaveštenja putem SMS-a)",
"attendee_email_workflow": "Imejl polaznika",
"attendee_email_variable": "Imejl polaznika",
"attendee_email_info": "Imejl osobe koja rezerviše",
"kbar_search_placeholder": "Unesite komandu ili pretražite...",
"invalid_credential": "O, ne! Izgleda da je dozvola istekla ili je povučena. Instalirajte ponovo.",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "Ny deltagare {{name}} i {{eventType}} {{date}}",
"new_seat_title": "Någon har lagt till sig själv i en händelse",
"variable": "Variabel",
"event_name_workflow": "Händelsenamn",
"organizer_name_workflow": "Arrangör",
"attendee_name_workflow": "Deltagare",
"event_date_workflow": "Händelsedatum",
"event_time_workflow": "Händelsetid",
"location_workflow": "Plats",
"additional_notes_workflow": "Ytterligare inmatning",
"event_name_variable": "Händelsenamn",
"organizer_name_variable": "Arrangör",
"attendee_name_variable": "Deltagare",
"event_date_variable": "Händelsedatum",
"event_time_variable": "Händelsetid",
"location_variable": "Plats",
"additional_notes_variable": "Ytterligare inmatning",
"app_upgrade_description": "För att kunna använda den här funktionen måste du uppgradera till ett Pro-konto.",
"invalid_number": "Ogiltigt telefonnummer",
"navigate": "Navigera",
@@ -1387,7 +1387,7 @@
"team_url_taken": "Denna URL används redan",
"team_publish": "Publicera team",
"number_sms_notifications": "Telefonnummer (SMS-notiser)",
"attendee_email_workflow": "Deltagarens e-postadress",
"attendee_email_variable": "Deltagarens e-postadress",
"attendee_email_info": "Personens e-postadress för bokning",
"kbar_search_placeholder": "Skriv ett kommando eller sök...",
"invalid_credential": "Åh nej! Det verkar som om behörigheten löpt ut eller återkallats. Installera om igen.",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "{{date}} tarihindeki {{eventType}} etkinliği için Yeni Katılımcı ({{name}})",
"new_seat_title": "Biri kendini bir etkinliğe ekledi",
"variable": "Değişken",
"event_name_workflow": "Etkinlik adı",
"organizer_name_workflow": "Düzenleyen Kişi",
"attendee_name_workflow": "Katılımcı",
"event_date_workflow": "Etkinlik tarihi",
"event_time_workflow": "Etkinlik saati",
"location_workflow": "Konum",
"additional_notes_workflow": "Ek notlar",
"event_name_variable": "Etkinlik adı",
"organizer_name_variable": "Düzenleyen Kişi",
"attendee_name_variable": "Katılımcı",
"event_date_variable": "Etkinlik tarihi",
"event_time_variable": "Etkinlik saati",
"location_variable": "Konum",
"additional_notes_variable": "Ek notlar",
"app_upgrade_description": "Bu özelliği kullanmak için Pro hesabına geçmeniz gerekiyor.",
"invalid_number": "Geçersiz telefon numarası",
"navigate": "Gezin",
@@ -1387,7 +1387,7 @@
"team_url_taken": "Bu URL zaten kullanılıyor",
"team_publish": "Ekibi yayınla",
"number_sms_notifications": "Telefon numarası (SMS bildirimleri)",
"attendee_email_workflow": "Katılımcı e-postası",
"attendee_email_variable": "Katılımcı e-postası",
"attendee_email_info": "Rezervasyon yaptıran kişinin e-postası",
"kbar_search_placeholder": "Bir komut girin veya arayın...",
"invalid_credential": "Hata! İznin süresi dolmuş veya iptal edilmiş gibi görünüyor. Lütfen yeniden yükleyin.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Новий учасник: {{name}} – {{eventType}}, {{date}}",
"new_seat_title": "Хтось додав себе в захід",
"variable": "Змінна",
"event_name_workflow": "Назва заходу",
"organizer_name_workflow": "Організатор",
"attendee_name_workflow": "Учасник",
"event_date_workflow": "Дата заходу",
"event_time_workflow": "Час заходу",
"location_workflow": "Розташування",
"additional_notes_workflow": "Додаткові примітки",
"event_name_variable": "Назва заходу",
"organizer_name_variable": "Організатор",
"attendee_name_variable": "Учасник",
"event_date_variable": "Дата заходу",
"event_time_variable": "Час заходу",
"location_variable": "Розташування",
"additional_notes_variable": "Додаткові примітки",
"app_upgrade_description": "Щоб користуватися цією функцією, потрібен обліковий запис Pro.",
"invalid_number": "Недійсний номер телефону",
"navigate": "Перейти",
@@ -1386,7 +1386,7 @@
"team_url_taken": "Цю URL-адресу вже зайнято",
"team_publish": "Опублікувати команду",
"number_sms_notifications": "Номер телефону (SMS-сповіщення)",
"attendee_email_workflow": "Адреса ел. пошти учасника",
"attendee_email_variable": "Адреса ел. пошти учасника",
"attendee_email_info": "Адреса ел. пошти особи, яка бронює",
"kbar_search_placeholder": "Введіть команду або пошуковий запис…",
"invalid_credential": "Отакої! Схоже, дозвіл більше не дійсний або його відкликано. Перевстановіть додаток знову.",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "Người tham gia mới tên {{name}} ở {{eventType}} vào {{date}}",
"new_seat_title": "Ai đó đã tự thêm chính họ vào một sự kiện",
"variable": "Biến số",
"event_name_workflow": "Tên sự kiện",
"organizer_name_workflow": "Tên nhà tổ chức",
"attendee_name_workflow": "Tên người tham dự",
"event_date_workflow": "Ngày sự kiện",
"event_time_workflow": "Thời gian sự kiện",
"location_workflow": "Vị trí",
"additional_notes_workflow": "Ghi chú bổ sung",
"event_name_variable": "Tên sự kiện",
"organizer_name_variable": "Tên nhà tổ chức",
"attendee_name_variable": "Tên người tham dự",
"event_date_variable": "Ngày sự kiện",
"event_time_variable": "Thời gian sự kiện",
"location_variable": "Vị trí",
"additional_notes_variable": "Ghi chú bổ sung",
"app_upgrade_description": "Để sử dụng tính năng này, bạn cần nâng cấp lên tài khoản Pro.",
"invalid_number": "Số điện thoại không hợp lệ",
"navigate": "Điều hướng",
@@ -1386,7 +1386,7 @@
"team_url_taken": "URL này đã có người lấy rồi",
"team_publish": "Đăng nhóm",
"number_sms_notifications": "Số điện thoại (thông báo SMS)",
"attendee_email_workflow": "Email người tham dự",
"attendee_email_variable": "Email người tham dự",
"attendee_email_info": "Email người tham gia lịch hẹn",
"kbar_search_placeholder": "Nhập một lệnh hoặc tìm kiếm...",
"invalid_credential": "Ôi không! Có vẻ như quyền đã hết hạn hoặc đã bị thu hồi. Vui lòng cài đặt lại.",
@@ -1077,13 +1077,13 @@
"new_seat_subject": "{{date}} 的 {{eventType}} 有新参与者 {{name}}",
"new_seat_title": "有人将自己添加到活动中",
"variable": "变量",
"event_name_workflow": "活动名称",
"organizer_name_workflow": "组织者",
"attendee_name_workflow": "参与者",
"event_date_workflow": "活动日期",
"event_time_workflow": "活动时间",
"location_workflow": "位置",
"additional_notes_workflow": "附加备注",
"event_name_variable": "活动名称",
"organizer_name_variable": "组织者",
"attendee_name_variable": "参与者",
"event_date_variable": "活动日期",
"event_time_variable": "活动时间",
"location_variable": "位置",
"additional_notes_variable": "附加备注",
"app_upgrade_description": "要使用此功能,您需要升级到专业版帐户。",
"invalid_number": "电话号码无效",
"navigate": "导航",
@@ -1387,7 +1387,7 @@
"team_url_taken": "此链接已被占用",
"team_publish": "发布团队",
"number_sms_notifications": "电话号码(短信通知)",
"attendee_email_workflow": "参与者电子邮件",
"attendee_email_variable": "参与者电子邮件",
"attendee_email_info": "预约人的电子邮件",
"kbar_search_placeholder": "输入命令或搜索...",
"invalid_credential": "哦不!看起来权限已过期或被撤销。请重新安装。",
@@ -1076,13 +1076,13 @@
"new_seat_subject": "{{date}} 的 {{eventType}} 有新與會者 {{name}}",
"new_seat_title": "有人將自己加入活動中",
"variable": "變數",
"event_name_workflow": "活動名稱",
"organizer_name_workflow": "主辦者姓名",
"attendee_name_workflow": "與會者姓名",
"event_date_workflow": "活動日期",
"event_time_workflow": "活動時間",
"location_workflow": "地點",
"additional_notes_workflow": "備註",
"event_name_variable": "活動名稱",
"organizer_name_variable": "主辦者姓名",
"attendee_name_variable": "與會者姓名",
"event_date_variable": "活動日期",
"event_time_variable": "活動時間",
"location_variable": "地點",
"additional_notes_variable": "備註",
"app_upgrade_description": "您必須升級至專業版帳號才能使用此功能。",
"invalid_number": "電話號碼無效",
"navigate": "導覽",
@@ -1386,7 +1386,7 @@
"team_url_taken": "已有人使用此網址",
"team_publish": "發佈團隊",
"number_sms_notifications": "電話號碼 (簡訊通知)",
"attendee_email_workflow": "與會者電子郵件",
"attendee_email_variable": "與會者電子郵件",
"attendee_email_info": "預約人電子郵件",
"kbar_search_placeholder": "輸入指令或搜尋…",
"invalid_credential": "糟糕!權限似乎過期或遭到撤銷。請重新安裝。",
@@ -72,13 +72,13 @@ const WorkflowListItem = (props: ItemProps) => {
workflow.steps.forEach((step) => {
switch (step.action) {
case WorkflowActions.EMAIL_HOST:
sendTo.add(t("organizer_name_workflow"));
sendTo.add(t("organizer_name_variable"));
break;
case WorkflowActions.EMAIL_ATTENDEE:
sendTo.add(t("attendee_name_workflow"));
sendTo.add(t("attendee_name_variable"));
break;
case WorkflowActions.SMS_ATTENDEE:
sendTo.add(t("attendee_name_workflow"));
sendTo.add(t("attendee_name_variable"));
break;
case WorkflowActions.SMS_NUMBER:
sendTo.add(step.sendTo || "");
@@ -34,13 +34,13 @@ import {
showToast,
TextArea,
TextField,
Editor,
AddVariablesDropdown,
} from "@calcom/ui";
import { AddVariablesDropdown } from "../components/AddVariablesDropdown";
import { getWorkflowTemplateOptions, getWorkflowTriggerOptions } from "../lib/getOptions";
import { translateVariablesToEnglish } from "../lib/variableTranslations";
import type { FormValues } from "../pages/workflow";
import Editor from "./TextEditor/Editor";
import { TimeTimeUnitInput } from "./TimeTimeUnitInput";
type WorkflowStepProps = {
@@ -50,6 +50,18 @@ type WorkflowStepProps = {
setReload?: Dispatch<SetStateAction<boolean>>;
};
const dynamicTextVariables = [
"event_name",
"event_date",
"event_time",
"location",
"organizer_name",
"attendee_name",
"attendee_email",
"additional_notes",
"meeting_url",
];
export default function WorkflowStepContainer(props: WorkflowStepProps) {
const { t, i18n } = useLocale();
const utils = trpc.useContext();
@@ -117,23 +129,25 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
: false
);
const addVariable = (variable: string, isEmailSubject?: boolean) => {
const addVariableBody = (variable: string) => {
if (step) {
if (isEmailSubject) {
const currentEmailSubject = refEmailSubject?.current?.value || "";
const cursorPosition = refEmailSubject?.current?.selectionStart || currentEmailSubject.length;
const subjectWithAddedVariable = `${currentEmailSubject.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(/ /g, "_")}}${currentEmailSubject.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.emailSubject`, subjectWithAddedVariable);
} else {
const currentMessageBody = refReminderBody?.current?.value || "";
const cursorPosition = refReminderBody?.current?.selectionStart || currentMessageBody.length;
const messageWithAddedVariable = `${currentMessageBody.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(/ /g, "_")}}${currentMessageBody.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, messageWithAddedVariable);
}
const currentMessageBody = refReminderBody?.current?.value || "";
const cursorPosition = refReminderBody?.current?.selectionStart || currentMessageBody.length;
const messageWithAddedVariable = `${currentMessageBody.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(/ /g, "_")}}${currentMessageBody.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, messageWithAddedVariable);
}
};
const addVariableEmailSubject = (variable: string) => {
if (step) {
const currentEmailSubject = refEmailSubject?.current?.value || "";
const cursorPosition = refEmailSubject?.current?.selectionStart || currentEmailSubject.length;
const subjectWithAddedVariable = `${currentEmailSubject.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(/ /g, "_")}}${currentEmailSubject.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.emailSubject`, subjectWithAddedVariable);
}
};
@@ -541,7 +555,10 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
<div className="flex items-center">
<Label className="mb-0 flex-none">{t("subject")}</Label>
<div className="flex-grow text-right">
<AddVariablesDropdown addVariable={addVariable} isEmailSubject={true} />
<AddVariablesDropdown
addVariable={addVariableEmailSubject}
variables={dynamicTextVariables}
/>
</div>
</div>
<TextArea
@@ -571,7 +588,16 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
</div>
<Editor form={form} stepNumber={step.stepNumber} />
<Editor
getText={() => {
return props.form.getValues(`steps.${step.stepNumber - 1}.reminderBody`) || "";
}}
setText={(text: string) => {
props.form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, text);
props.form.clearErrors();
}}
variables={dynamicTextVariables}
/>
</>
) : (
<>
@@ -580,7 +606,10 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
<div className="flex-grow text-right">
<AddVariablesDropdown addVariable={addVariable} isEmailSubject={false} />
<AddVariablesDropdown
addVariable={addVariableBody}
variables={dynamicTextVariables}
/>
</div>
</div>
<TextArea
@@ -1,15 +1,15 @@
import { TFunction } from "next-i18next";
const originalVariables = [
"event_name_workflow",
"organizer_name_workflow",
"attendee_name_workflow",
"event_date_workflow",
"event_time_workflow",
"location_workflow",
"additional_notes_workflow",
"attendee_email_workflow",
"meeting_url_workflow",
"event_name_variable",
"organizer_name_variable",
"attendee_name_variable",
"event_date_variable",
"event_time_variable",
"location_variable",
"additional_notes_variable",
"attendee_email_variable",
"meeting_url_variable",
];
export function getTranslatedText(text: string, language: { locale: string; t: TFunction }) {
@@ -21,14 +21,14 @@ export function getTranslatedText(text: string, language: { locale: string; t: T
});
variables?.forEach((variable) => {
const regex = new RegExp(variable, "g"); // .replaceAll is not available here for some reason
const translatedVariable = originalVariables.includes(variable.toLowerCase().concat("_workflow"))
? language.t(variable.toLowerCase().concat("_workflow")).replace(/ /g, "_").toLocaleUpperCase()
: originalVariables.includes(variable.toLowerCase().concat("_name_workflow")) //for the old variables names (ORGANIZER_NAME, ATTENDEE_NAME)
? language.t(variable.toLowerCase().concat("_name_workflow")).replace(/ /g, "_").toLocaleUpperCase()
const regex = new RegExp(`{${variable}}`, "g"); // .replaceAll is not available here for some reason
const translatedVariable = originalVariables.includes(variable.toLowerCase().concat("_variable"))
? language.t(variable.toLowerCase().concat("_variable")).replace(/ /g, "_").toLocaleUpperCase()
: originalVariables.includes(variable.toLowerCase().concat("_name_variable")) //for the old variables names (ORGANIZER_NAME, ATTENDEE_NAME)
? language.t(variable.toLowerCase().concat("_name_variable")).replace(/ /g, "_").toLocaleUpperCase()
: variable;
translatedText = translatedText.replace(regex, translatedVariable);
translatedText = translatedText.replace(regex, `{${translatedVariable}}`);
});
}
@@ -11,28 +11,32 @@ import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPl
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import { UseFormReturn } from "react-hook-form";
import { FormValues } from "../../pages/workflow";
import ExampleTheme from "./ExampleTheme";
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
import ToolbarPlugin from "./plugins/ToolbarPlugin";
import "./stylesEditor.css";
/*
Detault toolbar items:
- blockType
- bold
- italic
- link
*/
export type TextEditorProps = {
form: UseFormReturn<FormValues>;
stepNumber: number;
getText: () => string;
setText: (text: string) => void;
excludedToolbarItems?: string[];
variables?: string[];
};
const editorConfig = {
// The editor theme
theme: ExampleTheme,
// Handling of errors during update
onError(error: any) {
throw error;
},
namespace: "",
// Any custom nodes go here
nodes: [
HeadingNode,
ListNode,
@@ -48,12 +52,17 @@ const editorConfig = {
],
};
export default function Editor(props: TextEditorProps) {
export const Editor = (props: TextEditorProps) => {
return (
<div className="editor">
<LexicalComposer initialConfig={editorConfig}>
<div className="editor-container">
<ToolbarPlugin form={props.form} stepNumber={props.stepNumber} />
<ToolbarPlugin
getText={props.getText}
setText={props.setText}
excludedToolbarItems={props.excludedToolbarItems}
variables={props.variables}
/>
<div className="editor-inner">
<RichTextPlugin contentEditable={<ContentEditable className="editor-input" />} placeholder="" />
<AutoFocusPlugin />
@@ -66,4 +75,4 @@ export default function Editor(props: TextEditorProps) {
</LexicalComposer>
</div>
);
}
};

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 404 B

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 984 B

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 448 B

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 590 B

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 418 B

Before

Width:  |  Height:  |  Size: 471 B

After

Width:  |  Height:  |  Size: 471 B

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 283 B

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 483 B

Before

Width:  |  Height:  |  Size: 352 B

After

Width:  |  Height:  |  Size: 352 B

+2
View File
@@ -0,0 +1,2 @@
export { Editor } from "./Editor";
export { AddVariablesDropdown } from "./plugins/AddVariablesDropdown";
@@ -2,23 +2,11 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Dropdown, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Icon } from "@calcom/ui";
interface IAddVariablesDropdown {
addVariable: (variable: string, isEmailSubject?: boolean) => void;
isEmailSubject?: boolean;
addVariable: (variable: string) => void;
isTextEditor?: boolean;
variables: string[];
}
const variables = [
"event_name",
"event_date",
"event_time",
"location",
"organizer_name",
"attendee_name",
"attendee_email",
"additional_notes",
"meeting_url",
];
export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
const { t } = useLocale();
@@ -47,16 +35,16 @@ export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
<div className="mb-2 px-4 text-left text-xs text-gray-500">
{t("add_dynamic_variables").toLocaleUpperCase()}
</div>
{variables.map((variable) => (
{props.variables.map((variable) => (
<DropdownMenuItem key={variable} className="hover:ring-0">
<button
key={variable}
type="button"
className="w-full px-4 py-2"
onClick={() => props.addVariable(t(`${variable}_workflow`), props.isEmailSubject)}>
onClick={() => props.addVariable(t(`${variable}_variable`))}>
<div className="sm:grid sm:grid-cols-2">
<div className="mr-3 text-left md:col-span-1">
{`{${t(`${variable}_workflow`).toUpperCase().replace(/ /g, "_")}}`}
{`{${t(`${variable}_variable`).toUpperCase().replace(/ /g, "_")}}`}
</div>
<div className="hidden text-left text-gray-600 sm:col-span-1 sm:flex">
{t(`${variable}_info`)}
@@ -11,6 +11,7 @@ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext
import { $createHeadingNode, $isHeadingNode } from "@lexical/rich-text";
import { $wrapNodes, $isAtNodeEnd } from "@lexical/selection";
import { $getNearestNodeOfType, mergeRegister } from "@lexical/utils";
import classNames from "classnames";
import {
SELECTION_CHANGE_COMMAND,
FORMAT_TEXT_COMMAND,
@@ -25,14 +26,20 @@ import {
LexicalEditor,
EditorState,
} from "lexical";
import { RefObject, Dispatch, SetStateAction } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Icon } from "@calcom/ui";
import {
Icon,
Dropdown,
DropdownMenuTrigger,
DropdownMenuItem,
DropdownMenuContent,
Button,
} from "@calcom/ui";
import { AddVariablesDropdown } from "../../AddVariablesDropdown";
import { TextEditorProps } from "../Editor";
import { AddVariablesDropdown } from "./AddVariablesDropdown";
const LowPriority = 1;
@@ -43,11 +50,11 @@ interface BlockType {
}
const blockTypeToBlockName: BlockType = {
paragraph: "Normal",
ol: "Numbered List",
ul: "Bulleted List",
h1: "Large Heading",
h2: "Small Heading",
ol: "Numbered List",
paragraph: "Normal",
ul: "Bulleted List",
};
function positionEditorElement(editor: HTMLInputElement, rect: DOMRect | null) {
@@ -220,51 +227,13 @@ function getSelectedNode(selection: RangeSelection) {
}
}
type BlockOptionsDropdownProps = {
editor: LexicalEditor;
blockType: string;
toolbarRef: RefObject<HTMLDivElement>;
setShowBlockOptionsDropDown: Dispatch<SetStateAction<boolean>>;
};
function BlockOptionsDropdownList({
editor,
blockType,
toolbarRef,
setShowBlockOptionsDropDown,
}: BlockOptionsDropdownProps) {
const dropDownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const toolbar = toolbarRef.current;
const dropDown = dropDownRef.current;
if (toolbar !== null && dropDown) {
const { top, left } = toolbar.getBoundingClientRect();
dropDown.style.top = `${top + 40}px`;
dropDown.style.left = `${left}px`;
}
}, [dropDownRef, toolbarRef]);
useEffect(() => {
const dropDown = dropDownRef.current;
const toolbar = toolbarRef.current;
if (dropDown && toolbar !== null) {
const handle = (event: any) => {
const target = event.target;
if (!dropDown.contains(target) && !toolbar.contains(target)) {
setShowBlockOptionsDropDown(false);
}
};
document.addEventListener("click", handle);
return () => {
document.removeEventListener("click", handle);
};
}
}, [dropDownRef, setShowBlockOptionsDropDown, toolbarRef]);
export default function ToolbarPlugin(props: TextEditorProps) {
const [editor] = useLexicalComposerContext();
const toolbarRef = useRef(null);
const [blockType, setBlockType] = useState("paragraph");
const [isLink, setIsLink] = useState(false);
const [isBold, setIsBold] = useState(false);
const [isItalic, setIsItalic] = useState(false);
const formatParagraph = () => {
if (blockType !== "paragraph") {
@@ -276,7 +245,6 @@ function BlockOptionsDropdownList({
}
});
}
setShowBlockOptionsDropDown(false);
};
const formatLargeHeading = () => {
@@ -289,7 +257,6 @@ function BlockOptionsDropdownList({
}
});
}
setShowBlockOptionsDropDown(false);
};
const formatSmallHeading = () => {
@@ -302,7 +269,6 @@ function BlockOptionsDropdownList({
}
});
}
setShowBlockOptionsDropDown(false);
};
const formatBulletList = () => {
@@ -311,7 +277,6 @@ function BlockOptionsDropdownList({
} else {
editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
}
setShowBlockOptionsDropDown(false);
};
const formatNumberedList = () => {
@@ -320,48 +285,27 @@ function BlockOptionsDropdownList({
} else {
editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
}
setShowBlockOptionsDropDown(false);
};
return (
<div className="dropdown" ref={dropDownRef}>
<button type="button" className="item" onClick={formatParagraph}>
<span className="icon paragraph" />
<span className="text">Normal</span>
{blockType === "paragraph" && <span className="active" />}
</button>
<button type="button" className="item" onClick={formatBulletList}>
<span className="icon bullet-list" />
<span className="text">Bullet List</span>
{blockType === "ul" && <span className="active" />}
</button>
<button type="button" className="item" onClick={formatNumberedList}>
<span className="icon numbered-list" />
<span className="text">Numbered List</span>
{blockType === "ol" && <span className="active" />}
</button>
<button type="button" className="item" onClick={formatLargeHeading}>
<span className="icon large-heading" />
<span className="text">Large Heading</span>
{blockType === "h1" && <span className="active" />}
</button>
<button type="button" className="item" onClick={formatSmallHeading}>
<span className="icon small-heading" />
<span className="text">Small Heading</span>
{blockType === "h2" && <span className="active" />}
</button>
</div>
);
}
export default function ToolbarPlugin(props: TextEditorProps) {
const [editor] = useLexicalComposerContext();
const toolbarRef = useRef(null);
const [blockType, setBlockType] = useState("paragraph");
const [showBlockOptionsDropDown, setShowBlockOptionsDropDown] = useState(false);
const [isLink, setIsLink] = useState(false);
const [isBold, setIsBold] = useState(false);
const [isItalic, setIsItalic] = useState(false);
const format = (newBlockType: string) => {
switch (newBlockType) {
case "paragraph":
formatParagraph();
break;
case "ul":
formatBulletList();
break;
case "ol":
formatNumberedList();
break;
case "h1":
formatLargeHeading();
break;
case "h2":
formatSmallHeading();
break;
}
};
const updateToolbar = useCallback(() => {
const selection = $getSelection();
@@ -408,10 +352,7 @@ export default function ToolbarPlugin(props: TextEditorProps) {
useEffect(() => {
editor.update(() => {
const parser = new DOMParser();
const dom = parser.parseFromString(
props.form.getValues(`steps.${props.stepNumber - 1}.reminderBody`) || "",
"text/html"
);
const dom = parser.parseFromString(props.getText(), "text/html");
const nodes = $generateNodesFromDOM(editor, dom);
@@ -421,8 +362,7 @@ export default function ToolbarPlugin(props: TextEditorProps) {
editor.registerUpdateListener(({ editorState }) => {
editorState.read(() => {
const textInHtml = $generateHtmlFromNodes(editor);
props.form.setValue(`steps.${props.stepNumber - 1}.reminderBody`, textInHtml);
props.form.clearErrors();
props.setText(textInHtml);
});
});
});
@@ -457,69 +397,94 @@ export default function ToolbarPlugin(props: TextEditorProps) {
return (
<div className="toolbar flex" ref={toolbarRef}>
<>
{supportedBlockTypes.has(blockType) && (
{!props.excludedToolbarItems?.includes("blockType") && supportedBlockTypes.has(blockType) && (
<>
<button
type="button"
className="toolbar-item block-controls"
onClick={() => setShowBlockOptionsDropDown(!showBlockOptionsDropDown)}
aria-label="Formatting Options">
<span className={"icon block-type " + blockType} />
<span className="text hidden sm:flex">
{blockTypeToBlockName[blockType as keyof BlockType]}
</span>
<Icon.FiChevronDown className="h-4 w-4" />
</button>
{showBlockOptionsDropDown &&
createPortal(
<BlockOptionsDropdownList
editor={editor}
blockType={blockType}
toolbarRef={toolbarRef}
setShowBlockOptionsDropDown={setShowBlockOptionsDropDown}
/>,
document.body
)}
<Dropdown>
<DropdownMenuTrigger className="toolbar-item w-36 text-gray-500">
<>
<span className={"icon block-type " + blockType} />
<span className="text hidden text-gray-700 sm:flex">
{blockTypeToBlockName[blockType as keyof BlockType]}
</span>
<Icon.FiChevronDown className="ml-2 h-4 w-4 text-gray-700" />
</>
</DropdownMenuTrigger>
<DropdownMenuContent>
{Object.keys(blockTypeToBlockName).map((key) => {
return (
<DropdownMenuItem key={key} className="outline-none hover:ring-0 focus:ring-0">
<Button
color="minimal"
type="button"
onClick={() => format(key)}
className={classNames(
"toolbar-item w-full focus:ring-0",
blockType === key ? "w-full bg-gray-100" : ""
)}>
<>
<span className={"icon block-type " + key} />
<span>{blockTypeToBlockName[key]}</span>
</>
</Button>
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</Dropdown>
</>
)}
<>
<button
type="button"
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
if (isItalic) {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
}
}}
className={"toolbar-item spaced " + (isBold ? "active" : "")}
aria-label="Format Bold">
<i className="format bold" />
</button>
<button
type="button"
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
if (isBold) {
{!props.excludedToolbarItems?.includes("bold") && (
<button
type="button"
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
}
}}
className={"toolbar-item spaced " + (isItalic ? "active" : "")}
aria-label="Format Italics">
<i className="format italic" />
</button>
<button
type="button"
onClick={insertLink}
className={"toolbar-item spaced " + (isLink ? "active" : "")}
aria-label="Insert Link">
<i className="format link" />
</button>
{isLink && createPortal(<FloatingLinkEditor editor={editor} />, document.body)}{" "}
if (isItalic) {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
}
}}
className={"toolbar-item spaced " + (isBold ? "active" : "")}
aria-label="Format Bold">
<i className="format bold" />
</button>
)}
{!props.excludedToolbarItems?.includes("italic") && (
<button
type="button"
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
if (isBold) {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
}
}}
className={"toolbar-item spaced " + (isItalic ? "active" : "")}
aria-label="Format Italics">
<i className="format italic" />
</button>
)}
{!props.excludedToolbarItems?.includes("link") && (
<>
<button
type="button"
onClick={insertLink}
className={"toolbar-item spaced " + (isLink ? "active" : "")}
aria-label="Insert Link">
<i className="format link" />
</button>
{isLink && createPortal(<FloatingLinkEditor editor={editor} />, document.body)}{" "}
</>
)}
</>
<div className="ml-auto">
<AddVariablesDropdown addVariable={addVariable} isEmailSubject={false} isTextEditor={true} />
</div>
{props.variables && (
<div className="ml-auto">
<AddVariablesDropdown
addVariable={addVariable}
isTextEditor={true}
variables={props.variables || []}
/>
</div>
)}
</>
</div>
);
@@ -129,7 +129,6 @@ pre::-webkit-scrollbar-thumb {
.toolbar button.toolbar-item {
border: 0;
display: flex;
background: none;
border-radius: 10px;
padding: 8px;
cursor: pointer;
+1
View File
@@ -56,6 +56,7 @@ export { List, ListItem, ListItemText, ListItemTitle, ListLinkItem } from "./lis
export type { ListItemProps, ListProps } from "./list";
export { HeadSeo } from "./head-seo";
export { Skeleton, SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "./skeleton";
export { Editor, AddVariablesDropdown } from "./editor";
export {
Dialog,
DialogClose,
+2
View File
@@ -57,6 +57,8 @@ export {
AppStoreCategories,
Slider,
useShouldShowArrows,
Editor,
AddVariablesDropdown,
Dialog,
DialogClose,
DialogContent,