Parcourir la source

Team invitations go out through the email designer (#370)

Bernt Christian Egeland il y a 3 semaines
Parent
commit
bc0236c4c3

+ 9 - 0
messages/de/email.json

@@ -38,6 +38,15 @@
       "button": "Anmelden",
       "linkFallback": "Falls die Schaltfläche nicht funktioniert, kopieren Sie diesen Link in Ihren Browser:\n{signin_link}",
       "outro": "Dieser Link ist 15 Minuten gültig. Falls Sie ihn nicht angefordert haben, können Sie diese E-Mail ignorieren."
+    },
+    "team_invitation": {
+      "name": "Team-Einladung",
+      "subject": "Sie sind eingeladen, {workshop_name} beizutreten",
+      "heading": "Werden Sie Teil von {workshop_name}",
+      "intro": "Sie wurden eingeladen, {workshop_name} auf Torqvoice als {role} beizutreten.\n\nKlicken Sie auf die Schaltfläche unten, um Ihr Konto zu erstellen und dem Team beizutreten.",
+      "button": "Einladung annehmen",
+      "linkFallback": "Wenn die Schaltfläche nicht funktioniert, kopieren Sie diesen Link in Ihren Browser:\n{invite_link}",
+      "outro": "Diese Einladung gilt bis {invite_expires}. Wenn Sie sie nicht erwartet haben, können Sie diese E-Mail ignorieren."
     }
   },
   "attachmentNote": "Eine PDF-Kopie ist dieser E-Mail beigefügt.",

+ 20 - 2
messages/de/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Dokumente",
       "messages": "Nachrichten",
-      "portal": "Kundenportal"
+      "portal": "Kundenportal",
+      "team": "Team"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Portal-Anmeldung",
         "description": "Der Anmeldelink, den ein Kunde im Kundenportal anfordert."
+      },
+      "team_invitation": {
+        "name": "Team-Einladung",
+        "description": "Geht an eine Kollegin oder einen Kollegen, die Sie in die Werkstatt einladen, mit dem Link, der das Konto anlegt."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Fahrzeug",
       "document": "Dokument",
       "message": "Nachricht",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Team"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portallink",
         "description": "Ein Link zum Kundenportal."
+      },
+      "invite_link": {
+        "label": "Einladungslink",
+        "description": "Der Link, der das Konto anlegt und dem Team beitritt. Er funktioniert nicht mehr, sobald die Einladung abläuft."
+      },
+      "role": {
+        "label": "Rolle",
+        "description": "Die Rolle, in die die Person eingeladen wird."
+      },
+      "invite_expires": {
+        "label": "Ablaufdatum",
+        "description": "Der letzte Tag, an dem der Einladungslink funktioniert."
       }
     },
     "optionalTag": "Nicht jede E-Mail hat einen Wert für dieses Tag. Bleibt es leer, werden die Worte darum herum bereinigt.",

+ 9 - 0
messages/en/email.json

@@ -38,6 +38,15 @@
       "button": "Sign in",
       "linkFallback": "If the button does not work, copy this link into your browser:\n{signin_link}",
       "outro": "This link expires in 15 minutes. If you did not ask for it, you can ignore this email."
+    },
+    "team_invitation": {
+      "name": "Team invitation",
+      "subject": "You're invited to join {workshop_name}",
+      "heading": "Join {workshop_name}",
+      "intro": "You have been invited to join {workshop_name} on Torqvoice as {role}.\n\nUse the button below to create your account and join the team.",
+      "button": "Accept invitation",
+      "linkFallback": "If the button does not work, copy this link into your browser:\n{invite_link}",
+      "outro": "This invitation is valid until {invite_expires}. If you were not expecting it, you can ignore this email."
     }
   },
   "attachmentNote": "A PDF copy is attached to this email.",

+ 20 - 2
messages/en/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documents",
       "messages": "Messages",
-      "portal": "Customer portal"
+      "portal": "Customer portal",
+      "team": "Team"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Portal sign-in",
         "description": "The sign-in link a customer asks for on the customer portal."
+      },
+      "team_invitation": {
+        "name": "Team invitation",
+        "description": "Sent to a colleague you invite to join the workshop, with the link that creates their account."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Vehicle",
       "document": "Document",
       "message": "Message",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Team"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portal link",
         "description": "A link to the customer portal."
+      },
+      "invite_link": {
+        "label": "Invitation link",
+        "description": "The link that creates the account and joins the team. It stops working when the invitation expires."
+      },
+      "role": {
+        "label": "Role",
+        "description": "The role the person is invited as."
+      },
+      "invite_expires": {
+        "label": "Expiry date",
+        "description": "The last day the invitation link works."
       }
     },
     "optionalTag": "Not every email has a value for this tag. When it is blank, the words around it are tidied up.",

+ 9 - 0
messages/es/email.json

@@ -38,6 +38,15 @@
       "button": "Iniciar sesión",
       "linkFallback": "Si el botón no funciona, copie este enlace en su navegador:\n{signin_link}",
       "outro": "Este enlace caduca en 15 minutos. Si no lo ha solicitado, puede ignorar este correo."
+    },
+    "team_invitation": {
+      "name": "Invitación al equipo",
+      "subject": "Te han invitado a unirte a {workshop_name}",
+      "heading": "Únete a {workshop_name}",
+      "intro": "Te han invitado a unirte a {workshop_name} en Torqvoice como {role}.\n\nUsa el botón de abajo para crear tu cuenta y unirte al equipo.",
+      "button": "Aceptar invitación",
+      "linkFallback": "Si el botón no funciona, copia este enlace en tu navegador:\n{invite_link}",
+      "outro": "Esta invitación es válida hasta el {invite_expires}. Si no la esperabas, puedes ignorar este correo."
     }
   },
   "attachmentNote": "Adjuntamos una copia en PDF a este correo.",

+ 20 - 2
messages/es/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documentos",
       "messages": "Mensajes",
-      "portal": "Portal del cliente"
+      "portal": "Portal del cliente",
+      "team": "Equipo"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Acceso al portal",
         "description": "El enlace de acceso que un cliente solicita en el portal del cliente."
+      },
+      "team_invitation": {
+        "name": "Invitación al equipo",
+        "description": "Se envía a un compañero al que invitas a unirse al taller, con el enlace que crea su cuenta."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Vehículo",
       "document": "Documento",
       "message": "Mensaje",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Equipo"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Enlace del portal",
         "description": "Un enlace al portal del cliente."
+      },
+      "invite_link": {
+        "label": "Enlace de invitación",
+        "description": "El enlace que crea la cuenta y une al equipo. Deja de funcionar cuando caduca la invitación."
+      },
+      "role": {
+        "label": "Rol",
+        "description": "El rol con el que se invita a la persona."
+      },
+      "invite_expires": {
+        "label": "Fecha de caducidad",
+        "description": "El último día en que funciona el enlace de invitación."
       }
     },
     "optionalTag": "No todos los correos tienen un valor para esta etiqueta. Cuando está vacía, las palabras que la rodean se ordenan.",

+ 9 - 0
messages/fr/email.json

@@ -38,6 +38,15 @@
       "button": "Se connecter",
       "linkFallback": "Si le bouton ne fonctionne pas, copiez ce lien dans votre navigateur :\n{signin_link}",
       "outro": "Ce lien expire dans 15 minutes. Si vous n'en avez pas fait la demande, vous pouvez ignorer cet e-mail."
+    },
+    "team_invitation": {
+      "name": "Invitation dans l'équipe",
+      "subject": "Vous êtes invité à rejoindre {workshop_name}",
+      "heading": "Rejoignez {workshop_name}",
+      "intro": "Vous avez été invité à rejoindre {workshop_name} sur Torqvoice en tant que {role}.\n\nUtilisez le bouton ci-dessous pour créer votre compte et rejoindre l'équipe.",
+      "button": "Accepter l'invitation",
+      "linkFallback": "Si le bouton ne fonctionne pas, copiez ce lien dans votre navigateur :\n{invite_link}",
+      "outro": "Cette invitation est valable jusqu'au {invite_expires}. Si vous ne l'attendiez pas, vous pouvez ignorer cet e-mail."
     }
   },
   "attachmentNote": "Une copie PDF est jointe à cet e-mail.",

+ 20 - 2
messages/fr/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documents",
       "messages": "Messages",
-      "portal": "Portail client"
+      "portal": "Portail client",
+      "team": "Équipe"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Connexion au portail",
         "description": "Le lien de connexion qu'un client demande sur le portail client."
+      },
+      "team_invitation": {
+        "name": "Invitation dans l'équipe",
+        "description": "Envoyé à un collègue que vous invitez à rejoindre l'atelier, avec le lien qui crée son compte."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Véhicule",
       "document": "Document",
       "message": "Message",
-      "portal": "Portail"
+      "portal": "Portail",
+      "team": "Équipe"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Lien du portail",
         "description": "Un lien vers le portail client."
+      },
+      "invite_link": {
+        "label": "Lien d'invitation",
+        "description": "Le lien qui crée le compte et rejoint l'équipe. Il cesse de fonctionner à l'expiration de l'invitation."
+      },
+      "role": {
+        "label": "Rôle",
+        "description": "Le rôle auquel la personne est invitée."
+      },
+      "invite_expires": {
+        "label": "Date d'expiration",
+        "description": "Le dernier jour où le lien d'invitation fonctionne."
       }
     },
     "optionalTag": "Tous les e-mails n'ont pas de valeur pour cette balise. Quand elle est vide, les mots autour sont remis en ordre.",

+ 9 - 0
messages/it/email.json

@@ -38,6 +38,15 @@
       "button": "Accedi",
       "linkFallback": "Se il pulsante non funziona, copi questo link nel suo browser:\n{signin_link}",
       "outro": "Questo link scade tra 15 minuti. Se non l'ha richiesto, può ignorare questa email."
+    },
+    "team_invitation": {
+      "name": "Invito nel team",
+      "subject": "Sei stato invitato a unirti a {workshop_name}",
+      "heading": "Unisciti a {workshop_name}",
+      "intro": "Sei stato invitato a unirti a {workshop_name} su Torqvoice come {role}.\n\nUsa il pulsante qui sotto per creare il tuo account e unirti al team.",
+      "button": "Accetta l'invito",
+      "linkFallback": "Se il pulsante non funziona, copia questo link nel tuo browser:\n{invite_link}",
+      "outro": "Questo invito è valido fino al {invite_expires}. Se non lo aspettavi, puoi ignorare questa email."
     }
   },
   "attachmentNote": "Una copia in PDF è allegata a questa email.",

+ 20 - 2
messages/it/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documenti",
       "messages": "Messaggi",
-      "portal": "Portale clienti"
+      "portal": "Portale clienti",
+      "team": "Team"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Accesso al portale",
         "description": "Il link di accesso che un cliente richiede sul portale clienti."
+      },
+      "team_invitation": {
+        "name": "Invito nel team",
+        "description": "Inviata a un collega che inviti a unirsi all'officina, con il link che crea il suo account."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Veicolo",
       "document": "Documento",
       "message": "Messaggio",
-      "portal": "Portale"
+      "portal": "Portale",
+      "team": "Team"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Link portale",
         "description": "Un link al portale clienti."
+      },
+      "invite_link": {
+        "label": "Link di invito",
+        "description": "Il link che crea l'account e unisce al team. Smette di funzionare quando l'invito scade."
+      },
+      "role": {
+        "label": "Ruolo",
+        "description": "Il ruolo con cui la persona è invitata."
+      },
+      "invite_expires": {
+        "label": "Data di scadenza",
+        "description": "L'ultimo giorno in cui il link di invito funziona."
       }
     },
     "optionalTag": "Non tutte le email hanno un valore per questo tag. Quando è vuoto, le parole intorno vengono sistemate.",

+ 9 - 0
messages/lt/email.json

@@ -38,6 +38,15 @@
       "button": "Prisijungti",
       "linkFallback": "Jei mygtukas neveikia, nukopijuokite šią nuorodą į savo naršyklę:\n{signin_link}",
       "outro": "Ši nuoroda galioja 15 minučių. Jei jos neprašėte, galite nekreipti dėmesio į šį laišką."
+    },
+    "team_invitation": {
+      "name": "Kvietimas į komandą",
+      "subject": "Esate pakviesti prisijungti prie {workshop_name}",
+      "heading": "Prisijunkite prie {workshop_name}",
+      "intro": "Esate pakviesti prisijungti prie {workshop_name} sistemoje Torqvoice kaip {role}.\n\nPaspauskite mygtuką žemiau, kad susikurtumėte paskyrą ir prisijungtumėte prie komandos.",
+      "button": "Priimti kvietimą",
+      "linkFallback": "Jei mygtukas neveikia, nukopijuokite šią nuorodą į naršyklę:\n{invite_link}",
+      "outro": "Šis kvietimas galioja iki {invite_expires}. Jei jo nesitikėjote, galite nekreipti dėmesio į šį laišką."
     }
   },
   "attachmentNote": "Prie šio laiško pridėta PDF kopija.",

+ 20 - 2
messages/lt/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Dokumentai",
       "messages": "Žinutės",
-      "portal": "Klientų portalas"
+      "portal": "Klientų portalas",
+      "team": "Komanda"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Prisijungimas prie portalo",
         "description": "Prisijungimo nuoroda, kurios klientas paprašo klientų portale."
+      },
+      "team_invitation": {
+        "name": "Kvietimas į komandą",
+        "description": "Siunčiamas kolegai, kurį kviečiate prisijungti prie dirbtuvių, su nuoroda paskyrai sukurti."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Transporto priemonė",
       "document": "Dokumentas",
       "message": "Žinutė",
-      "portal": "Portalas"
+      "portal": "Portalas",
+      "team": "Komanda"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portalo nuoroda",
         "description": "Nuoroda į klientų portalą."
+      },
+      "invite_link": {
+        "label": "Kvietimo nuoroda",
+        "description": "Nuoroda, kuri sukuria paskyrą ir prijungia prie komandos. Nustoja veikti pasibaigus kvietimo galiojimui."
+      },
+      "role": {
+        "label": "Vaidmuo",
+        "description": "Vaidmuo, kuriam asmuo kviečiamas."
+      },
+      "invite_expires": {
+        "label": "Galiojimo data",
+        "description": "Paskutinė diena, kai kvietimo nuoroda veikia."
       }
     },
     "optionalTag": "Ne kiekvienas laiškas turi šios žymės reikšmę. Kai ji tuščia, aplinkiniai žodžiai sutvarkomi.",

+ 9 - 0
messages/nb/email.json

@@ -38,6 +38,15 @@
       "button": "Logg inn",
       "linkFallback": "Hvis knappen ikke virker, kan du kopiere denne lenken inn i nettleseren din:\n{signin_link}",
       "outro": "Lenken utløper om 15 minutter. Hvis du ikke ba om den, kan du se bort fra denne e-posten."
+    },
+    "team_invitation": {
+      "name": "Invitasjon til teamet",
+      "subject": "Du er invitert til å bli med i {workshop_name}",
+      "heading": "Bli med i {workshop_name}",
+      "intro": "Du er invitert til å bli med i {workshop_name} på Torqvoice som {role}.\n\nBruk knappen under for å opprette kontoen din og bli med i teamet.",
+      "button": "Godta invitasjonen",
+      "linkFallback": "Hvis knappen ikke virker, kan du kopiere denne lenken inn i nettleseren din:\n{invite_link}",
+      "outro": "Invitasjonen gjelder til {invite_expires}. Hvis du ikke ventet den, kan du se bort fra denne e-posten."
     }
   },
   "attachmentNote": "En PDF-kopi er vedlagt denne e-posten.",

+ 20 - 2
messages/nb/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Dokumenter",
       "messages": "Meldinger",
-      "portal": "Kundeportal"
+      "portal": "Kundeportal",
+      "team": "Team"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Portalinnlogging",
         "description": "Innloggingslenken en kunde ber om på kundeportalen."
+      },
+      "team_invitation": {
+        "name": "Invitasjon til teamet",
+        "description": "Sendes til en kollega du inviterer inn i verkstedet, med lenken som oppretter kontoen."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Kjøretøy",
       "document": "Dokument",
       "message": "Melding",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Team"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portallenke",
         "description": "En lenke til kundeportalen."
+      },
+      "invite_link": {
+        "label": "Invitasjonslenke",
+        "description": "Lenken som oppretter kontoen og legger personen til i teamet. Den slutter å virke når invitasjonen utløper."
+      },
+      "role": {
+        "label": "Rolle",
+        "description": "Rollen personen inviteres som."
+      },
+      "invite_expires": {
+        "label": "Utløpsdato",
+        "description": "Siste dag invitasjonslenken virker."
       }
     },
     "optionalTag": "Ikke alle e-poster har en verdi for denne taggen. Når den er tom, ryddes ordene rundt den opp.",

+ 9 - 0
messages/nl/email.json

@@ -38,6 +38,15 @@
       "button": "Aanmelden",
       "linkFallback": "Werkt de knop niet? Kopieer dan deze link in uw browser:\n{signin_link}",
       "outro": "Deze link verloopt over 15 minuten. Heeft u hier niet om gevraagd, dan kunt u deze e-mail negeren."
+    },
+    "team_invitation": {
+      "name": "Teamuitnodiging",
+      "subject": "U bent uitgenodigd om lid te worden van {workshop_name}",
+      "heading": "Word lid van {workshop_name}",
+      "intro": "U bent uitgenodigd om als {role} lid te worden van {workshop_name} op Torqvoice.\n\nGebruik de knop hieronder om uw account aan te maken en lid te worden van het team.",
+      "button": "Uitnodiging accepteren",
+      "linkFallback": "Als de knop niet werkt, kopieer dan deze link in uw browser:\n{invite_link}",
+      "outro": "Deze uitnodiging is geldig tot {invite_expires}. Als u deze niet verwachtte, kunt u deze e-mail negeren."
     }
   },
   "attachmentNote": "Een PDF-kopie is als bijlage bij deze e-mail gevoegd.",

+ 20 - 2
messages/nl/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documenten",
       "messages": "Berichten",
-      "portal": "Klantportaal"
+      "portal": "Klantportaal",
+      "team": "Team"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Portaalaanmelding",
         "description": "De aanmeldlink die een klant aanvraagt op het klantportaal."
+      },
+      "team_invitation": {
+        "name": "Teamuitnodiging",
+        "description": "Verstuurd naar een collega die u uitnodigt voor de werkplaats, met de link die het account aanmaakt."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Voertuig",
       "document": "Document",
       "message": "Bericht",
-      "portal": "Portaal"
+      "portal": "Portaal",
+      "team": "Team"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portaallink",
         "description": "Een link naar het klantportaal."
+      },
+      "invite_link": {
+        "label": "Uitnodigingslink",
+        "description": "De link die het account aanmaakt en bij het team voegt. Werkt niet meer zodra de uitnodiging verloopt."
+      },
+      "role": {
+        "label": "Rol",
+        "description": "De rol waarvoor de persoon wordt uitgenodigd."
+      },
+      "invite_expires": {
+        "label": "Vervaldatum",
+        "description": "De laatste dag waarop de uitnodigingslink werkt."
       }
     },
     "optionalTag": "Niet elke e-mail heeft een waarde voor deze tag. Als hij leeg is, worden de woorden eromheen opgeruimd.",

+ 9 - 0
messages/pl/email.json

@@ -38,6 +38,15 @@
       "button": "Zaloguj się",
       "linkFallback": "Jeśli przycisk nie działa, prosimy skopiować ten link do przeglądarki:\n{signin_link}",
       "outro": "Ten link wygasa za 15 minut. Jeśli nie prosili Państwo o niego, można zignorować tę wiadomość."
+    },
+    "team_invitation": {
+      "name": "Zaproszenie do zespołu",
+      "subject": "Zaproszenie do dołączenia do {workshop_name}",
+      "heading": "Dołącz do {workshop_name}",
+      "intro": "Zaproszono Cię do dołączenia do {workshop_name} w Torqvoice jako {role}.\n\nUżyj przycisku poniżej, aby utworzyć konto i dołączyć do zespołu.",
+      "button": "Przyjmij zaproszenie",
+      "linkFallback": "Jeśli przycisk nie działa, skopiuj ten link do przeglądarki:\n{invite_link}",
+      "outro": "Zaproszenie jest ważne do {invite_expires}. Jeśli się go nie spodziewasz, możesz zignorować tę wiadomość."
     }
   },
   "attachmentNote": "Kopia PDF jest załączona do tej wiadomości.",

+ 20 - 2
messages/pl/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Dokumenty",
       "messages": "Wiadomości",
-      "portal": "Portal klienta"
+      "portal": "Portal klienta",
+      "team": "Zespół"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Logowanie do portalu",
         "description": "Link logowania, o który klient prosi w portalu klienta."
+      },
+      "team_invitation": {
+        "name": "Zaproszenie do zespołu",
+        "description": "Wysyłane do współpracownika zaproszonego do warsztatu, z linkiem tworzącym konto."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Pojazd",
       "document": "Dokument",
       "message": "Wiadomość",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Zespół"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Link do portalu",
         "description": "Link do portalu klienta."
+      },
+      "invite_link": {
+        "label": "Link zaproszenia",
+        "description": "Link tworzący konto i dołączający do zespołu. Przestaje działać po wygaśnięciu zaproszenia."
+      },
+      "role": {
+        "label": "Rola",
+        "description": "Rola, do której zapraszana jest osoba."
+      },
+      "invite_expires": {
+        "label": "Data wygaśnięcia",
+        "description": "Ostatni dzień działania linku zaproszenia."
       }
     },
     "optionalTag": "Nie każdy e-mail ma wartość dla tego tagu. Gdy jest pusty, słowa wokół niego są porządkowane.",

+ 9 - 0
messages/pt-BR/email.json

@@ -38,6 +38,15 @@
       "button": "Entrar",
       "linkFallback": "Se o botão não funcionar, copie este link no seu navegador:\n{signin_link}",
       "outro": "Este link expira em 15 minutos. Se você não o solicitou, pode ignorar este e-mail."
+    },
+    "team_invitation": {
+      "name": "Convite para a equipe",
+      "subject": "Você foi convidado a entrar em {workshop_name}",
+      "heading": "Entre em {workshop_name}",
+      "intro": "Você foi convidado a entrar em {workshop_name} no Torqvoice como {role}.\n\nUse o botão abaixo para criar sua conta e entrar na equipe.",
+      "button": "Aceitar convite",
+      "linkFallback": "Se o botão não funcionar, copie este link no seu navegador:\n{invite_link}",
+      "outro": "Este convite é válido até {invite_expires}. Se você não o esperava, pode ignorar este e-mail."
     }
   },
   "attachmentNote": "Uma cópia em PDF está anexada a este e-mail.",

+ 20 - 2
messages/pt-BR/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Documentos",
       "messages": "Mensagens",
-      "portal": "Portal do cliente"
+      "portal": "Portal do cliente",
+      "team": "Equipe"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Acesso ao portal",
         "description": "O link de acesso que um cliente solicita no portal do cliente."
+      },
+      "team_invitation": {
+        "name": "Convite para a equipe",
+        "description": "Enviado a um colega que você convida para a oficina, com o link que cria a conta."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Veículo",
       "document": "Documento",
       "message": "Mensagem",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Equipe"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Link do portal",
         "description": "Um link para o portal do cliente."
+      },
+      "invite_link": {
+        "label": "Link do convite",
+        "description": "O link que cria a conta e entra na equipe. Deixa de funcionar quando o convite expira."
+      },
+      "role": {
+        "label": "Função",
+        "description": "A função para a qual a pessoa é convidada."
+      },
+      "invite_expires": {
+        "label": "Data de validade",
+        "description": "O último dia em que o link do convite funciona."
       }
     },
     "optionalTag": "Nem todo e-mail tem um valor para esta tag. Quando ela fica vazia, as palavras ao redor são ajustadas.",

+ 9 - 0
messages/ru/email.json

@@ -38,6 +38,15 @@
       "button": "Войти",
       "linkFallback": "Если кнопка не работает, скопируйте эту ссылку в адресную строку браузера:\n{signin_link}",
       "outro": "Ссылка действует 15 минут. Если вы её не запрашивали, просто проигнорируйте это письмо."
+    },
+    "team_invitation": {
+      "name": "Приглашение в команду",
+      "subject": "Вас приглашают присоединиться к {workshop_name}",
+      "heading": "Присоединяйтесь к {workshop_name}",
+      "intro": "Вас пригласили присоединиться к {workshop_name} в Torqvoice в роли {role}.\n\nНажмите кнопку ниже, чтобы создать аккаунт и войти в команду.",
+      "button": "Принять приглашение",
+      "linkFallback": "Если кнопка не работает, скопируйте эту ссылку в браузер:\n{invite_link}",
+      "outro": "Приглашение действует до {invite_expires}. Если вы его не ждали, просто проигнорируйте это письмо."
     }
   },
   "attachmentNote": "Копия в формате PDF приложена к этому письму.",

+ 20 - 2
messages/ru/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Документы",
       "messages": "Сообщения",
-      "portal": "Портал клиента"
+      "portal": "Портал клиента",
+      "team": "Команда"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Вход в портал",
         "description": "Ссылка для входа, которую клиент запрашивает на портале клиента."
+      },
+      "team_invitation": {
+        "name": "Приглашение в команду",
+        "description": "Отправляется коллеге, которого вы приглашаете в мастерскую, со ссылкой для создания аккаунта."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Автомобиль",
       "document": "Документ",
       "message": "Сообщение",
-      "portal": "Портал"
+      "portal": "Портал",
+      "team": "Команда"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Ссылка на портал",
         "description": "Ссылка на портал клиента."
+      },
+      "invite_link": {
+        "label": "Ссылка приглашения",
+        "description": "Ссылка, которая создаёт аккаунт и добавляет в команду. Перестаёт работать по истечении приглашения."
+      },
+      "role": {
+        "label": "Роль",
+        "description": "Роль, в которой приглашён человек."
+      },
+      "invite_expires": {
+        "label": "Срок действия",
+        "description": "Последний день, когда работает ссылка приглашения."
       }
     },
     "optionalTag": "Не у каждого письма есть значение для этого тега. Когда он пуст, слова вокруг него приводятся в порядок.",

+ 9 - 0
messages/tr/email.json

@@ -38,6 +38,15 @@
       "button": "Giriş yap",
       "linkFallback": "Düğme çalışmazsa bu bağlantıyı tarayıcınıza kopyalayın:\n{signin_link}",
       "outro": "Bu bağlantı 15 dakika içinde geçerliliğini yitirir. Bu isteği siz yapmadıysanız bu e-postayı yok sayabilirsiniz."
+    },
+    "team_invitation": {
+      "name": "Ekip daveti",
+      "subject": "{workshop_name} ekibine davet edildiniz",
+      "heading": "{workshop_name} ekibine katılın",
+      "intro": "Torqvoice'ta {workshop_name} ekibine {role} olarak davet edildiniz.\n\nHesabınızı oluşturup ekibe katılmak için aşağıdaki düğmeyi kullanın.",
+      "button": "Daveti kabul et",
+      "linkFallback": "Düğme çalışmazsa bu bağlantıyı tarayıcınıza kopyalayın:\n{invite_link}",
+      "outro": "Bu davet {invite_expires} tarihine kadar geçerlidir. Beklemiyorsanız bu e-postayı yok sayabilirsiniz."
     }
   },
   "attachmentNote": "Bu e-postaya bir PDF kopyası eklenmiştir.",

+ 20 - 2
messages/tr/settings.json

@@ -2001,7 +2001,8 @@
     "groups": {
       "documents": "Belgeler",
       "messages": "Mesajlar",
-      "portal": "Müşteri portalı"
+      "portal": "Müşteri portalı",
+      "team": "Ekip"
     },
     "kinds": {
       "invoice_sent": {
@@ -2023,6 +2024,10 @@
       "portal_signin": {
         "name": "Portal girişi",
         "description": "Müşterinin müşteri portalında istediği giriş bağlantısı."
+      },
+      "team_invitation": {
+        "name": "Ekip daveti",
+        "description": "Atölyeye davet ettiğiniz bir iş arkadaşına, hesabını oluşturan bağlantıyla gönderilir."
       }
     },
     "blocks": {
@@ -2055,7 +2060,8 @@
       "vehicle": "Araç",
       "document": "Belge",
       "message": "Mesaj",
-      "portal": "Portal"
+      "portal": "Portal",
+      "team": "Ekip"
     },
     "tags": {
       "workshop_name": {
@@ -2129,6 +2135,18 @@
       "portal_link": {
         "label": "Portal bağlantısı",
         "description": "Müşteri portalına bağlantı."
+      },
+      "invite_link": {
+        "label": "Davet bağlantısı",
+        "description": "Hesabı oluşturan ve ekibe katan bağlantı. Davet süresi dolduğunda çalışmaz."
+      },
+      "role": {
+        "label": "Rol",
+        "description": "Kişinin davet edildiği rol."
+      },
+      "invite_expires": {
+        "label": "Son geçerlilik tarihi",
+        "description": "Davet bağlantısının çalıştığı son gün."
       }
     },
     "optionalTag": "Her e-postada bu etiket için bir değer yoktur. Boş olduğunda çevresindeki sözcükler düzenlenir.",

+ 3 - 0
src/__tests__/features/team/invitation-rules.test.ts

@@ -26,6 +26,9 @@ vi.mock('@/lib/email', () => ({
   sendOrgMail: vi.fn(),
   getOrgFromAddress: vi.fn(),
 }))
+vi.mock('@/features/email/Lib/sendTemplatedMail', () => ({
+  sendTemplatedMail: vi.fn().mockResolvedValue({ subject: 'Team invitation' }),
+}))
 
 vi.mock('@/lib/features', () => ({
   getFeatures: vi.fn().mockResolvedValue({ maxUsers: 100 }),

+ 14 - 8
src/__tests__/features/team/resend-invitation.test.ts

@@ -9,9 +9,10 @@ vi.mock('next/headers', () => ({
   headers: vi.fn().mockResolvedValue(new Headers()),
   cookies: vi.fn().mockResolvedValue({ set: vi.fn(), get: vi.fn() }),
 }))
-vi.mock('@/lib/email', () => ({
-  sendOrgMail: vi.fn().mockResolvedValue(undefined),
-  getOrgFromAddress: vi.fn().mockResolvedValue('shop@example.com'),
+// The invitation leaves through the workshop's template like every other
+// mail; what this file checks is what the send is told, not how it looks.
+vi.mock('@/features/email/Lib/sendTemplatedMail', () => ({
+  sendTemplatedMail: vi.fn().mockResolvedValue({ subject: 'Team invitation' }),
 }))
 vi.mock('@/lib/audit', () => ({ logAudit: vi.fn().mockResolvedValue(undefined) }))
 vi.mock('@/lib/db', () => ({
@@ -24,7 +25,7 @@ vi.mock('@/lib/db', () => ({
 
 import { getCachedMembership, getCachedSession } from '@/lib/cached-session'
 import { db } from '@/lib/db'
-import { sendOrgMail } from '@/lib/email'
+import { sendTemplatedMail } from '@/features/email/Lib/sendTemplatedMail'
 import { resendInvitation } from '@/features/team/Actions/resendInvitation'
 
 const INVITATION = {
@@ -65,10 +66,15 @@ describe('resendInvitation', () => {
     const expiresAt = update.data.expiresAt as Date
     expect(expiresAt.getTime()).toBeGreaterThan(Date.now() + 6 * 24 * 60 * 60 * 1000)
 
-    const mail = vi.mocked(sendOrgMail).mock.calls[0][1]
+    const [orgId, mail] = vi.mocked(sendTemplatedMail).mock.calls[0]
+    expect(orgId).toBe('org-1')
+    expect(mail.kind).toBe('team_invitation')
     expect(mail.to).toBe('new@example.com')
-    expect(mail.html).toContain(`invite=${update.data.token}`)
-    expect(mail.html).not.toContain('old-token')
+    const context = mail.context as { inviteLink: string; role: string; expiresAt: Date }
+    expect(context.inviteLink).toContain(`invite=${update.data.token}`)
+    expect(context.inviteLink).not.toContain('old-token')
+    expect(context.role).toBe('member')
+    expect(context.expiresAt).toBe(expiresAt)
   })
 
   it("only finds invitations of the caller's own workshop", async () => {
@@ -82,6 +88,6 @@ describe('resendInvitation', () => {
     signIn('member')
     const result = await resendInvitation({ invitationId: 'inv-1' })
     expect(result.success).toBe(false)
-    expect(sendOrgMail).not.toHaveBeenCalled()
+    expect(sendTemplatedMail).not.toHaveBeenCalled()
   })
 })

+ 5 - 1
src/__tests__/multitenancy/team-invite-isolation.test.ts

@@ -28,6 +28,9 @@ vi.mock('@/lib/email', () => ({
   sendOrgMail: vi.fn(),
   getOrgFromAddress: vi.fn(),
 }))
+vi.mock('@/features/email/Lib/sendTemplatedMail', () => ({
+  sendTemplatedMail: vi.fn().mockResolvedValue({ subject: 'Team invitation' }),
+}))
 
 vi.mock('@/lib/db', () => ({
   db: {
@@ -58,6 +61,7 @@ import { getCachedSession, getCachedMembership } from '@/lib/cached-session'
 import { db } from '@/lib/db'
 import { cookies } from 'next/headers'
 import { sendOrgMail, getOrgFromAddress } from '@/lib/email'
+import { sendTemplatedMail } from '@/features/email/Lib/sendTemplatedMail'
 import { acceptInvitation } from '@/features/team/Actions/acceptInvitation'
 import { sendInvitation } from '@/features/team/Actions/sendInvitation'
 import { cancelInvitation } from '@/features/team/Actions/cancelInvitation'
@@ -408,7 +412,7 @@ describe('sendInvitation — org scoping and role validation', () => {
   })
 
   it('rolls back the invitation record when the email send fails', async () => {
-    mockSendOrgMail.mockRejectedValue(new Error('SMTP error') as any)
+    vi.mocked(sendTemplatedMail).mockRejectedValueOnce(new Error('SMTP error'))
     vi.mocked(db.teamInvitation.delete).mockResolvedValue({} as any)
 
     const result = await sendInvitation({ email: 'new@example.com', role: 'member' })

+ 2 - 1
src/app/(authenticated)/settings/email-templates/email-template-gallery.tsx

@@ -1,6 +1,6 @@
 'use client'
 
-import { FileText, KeyRound, Loader2, MessageSquare, Trash2 } from 'lucide-react'
+import { FileText, KeyRound, Loader2, MessageSquare, Trash2, Users } from 'lucide-react'
 import Link from 'next/link'
 import { useRouter } from 'next/navigation'
 import { useFormatter, useTranslations } from 'next-intl'
@@ -28,6 +28,7 @@ const GROUP_ICONS: Record<EmailKindGroup, typeof FileText> = {
   documents: FileText,
   messages: MessageSquare,
   portal: KeyRound,
+  team: Users,
 }
 
 /**

+ 22 - 0
src/features/email/Lib/emailContext.ts

@@ -63,12 +63,22 @@ export interface PortalSigninEmailContext extends BaseContext {
   signinLink: string
 }
 
+export interface TeamInvitationEmailContext extends BaseContext {
+  /** The sign-up link carrying the invitation token. */
+  inviteLink: string
+  /** The role the person is invited as, in the workshop's own words. */
+  role?: string | null
+  /** When the link stops working. */
+  expiresAt?: Date | string | null
+}
+
 export type EmailContextByKind = {
   invoice_sent: DocumentEmailContext
   quote_sent: DocumentEmailContext
   inspection_sent: DocumentEmailContext
   message: MessageEmailContext
   portal_signin: PortalSigninEmailContext
+  team_invitation: TeamInvitationEmailContext
 }
 
 export type EmailContext<K extends EmailKind = EmailKind> = EmailContextByKind[K]
@@ -125,6 +135,8 @@ export function tagValuesFor<K extends EmailKind>(
   const fmt = doc ? money(doc) : undefined
   const balance = doc ? balanceOf(doc) : null
   const dueDate = asDate(doc?.dueDate)
+  const invitation = context as TeamInvitationEmailContext
+  const inviteExpires = asDate(invitation.expiresAt)
 
   const all: TagValues = {
     workshop_name: text(workshop.name),
@@ -145,6 +157,9 @@ export function tagValuesFor<K extends EmailKind>(
     message: text(base.message),
     signin_link: text((context as PortalSigninEmailContext).signinLink),
     portal_link: text((context as MessageEmailContext).portalLink),
+    invite_link: text(invitation.inviteLink),
+    role: text(invitation.role),
+    invite_expires: inviteExpires ? formatDate(inviteExpires) : undefined,
   }
 
   const values: TagValues = {}
@@ -240,6 +255,13 @@ export function sampleContextFor(kind: EmailKind, currentUser?: string | null):
   switch (kind) {
     case 'portal_signin':
       return { ...base, signinLink: TAGS.signin_link.sample }
+    case 'team_invitation':
+      return {
+        ...base,
+        inviteLink: TAGS.invite_link.sample,
+        role: TAGS.role.sample,
+        expiresAt: new Date('2026-09-16T12:00:00Z'),
+      }
     case 'message':
       return { ...base, message: TAGS.message.sample, portalLink: TAGS.portal_link.sample }
     default:

+ 17 - 2
src/features/email/Lib/emailKinds.ts

@@ -15,13 +15,19 @@ export const EMAIL_KINDS = [
   'inspection_sent',
   'message',
   'portal_signin',
+  'team_invitation',
 ] as const
 
 export type EmailKind = (typeof EMAIL_KINDS)[number]
 
-export type EmailKindGroup = 'documents' | 'messages' | 'portal'
+export type EmailKindGroup = 'documents' | 'messages' | 'portal' | 'team'
 
-export const EMAIL_KIND_GROUPS: readonly EmailKindGroup[] = ['documents', 'messages', 'portal']
+export const EMAIL_KIND_GROUPS: readonly EmailKindGroup[] = [
+  'documents',
+  'messages',
+  'portal',
+  'team',
+]
 
 export interface EmailKindSpec {
   group: EmailKindGroup
@@ -93,6 +99,15 @@ export const EMAIL_KIND_SPECS: Record<EmailKind, EmailKindSpec> = {
     hasSummary: false,
     hasAttachment: false,
   },
+  // Sent to a colleague, not a customer: the sender is the one inviting,
+  // and the link creates an account rather than opening a document.
+  team_invitation: {
+    group: 'team',
+    tags: [...WORKSHOP, 'invite_link', 'role', 'invite_expires'],
+    required: ['invite_link'],
+    hasSummary: false,
+    hasAttachment: false,
+  },
 }
 
 export function isEmailKind(value: string): value is EmailKind {

+ 6 - 1
src/features/email/Lib/emailPresets.ts

@@ -54,7 +54,12 @@ function presetBlocks(kind: EmailKind, words: PresetWords, attachmentNote: strin
   if (spec.hasSummary) blocks.push(block({ id: 'summary', type: 'document_summary' }))
 
   if (words.button) {
-    const href = kind === 'portal_signin' ? '{signin_link}' : '{share_link}'
+    const href =
+      kind === 'portal_signin'
+        ? '{signin_link}'
+        : kind === 'team_invitation'
+          ? '{invite_link}'
+          : '{share_link}'
     blocks.push(block({ id: 'cta', type: 'button', label: words.button, href }))
   }
   if (words.linkFallback) {

+ 13 - 1
src/features/email/Lib/tags.ts

@@ -19,7 +19,14 @@
  *   failure a stranger's row deserves.
  */
 
-export type TagGroup = 'workshop' | 'customer' | 'vehicle' | 'document' | 'message' | 'portal'
+export type TagGroup =
+  | 'workshop'
+  | 'customer'
+  | 'vehicle'
+  | 'document'
+  | 'message'
+  | 'portal'
+  | 'team'
 
 export interface TagSpec {
   group: TagGroup
@@ -57,6 +64,10 @@ export const TAGS = {
 
   signin_link: { group: 'portal', sample: 'https://example.com/portal/sign-in/preview' },
   portal_link: { group: 'portal', sample: 'https://example.com/portal/preview', optional: true },
+
+  invite_link: { group: 'team', sample: 'https://example.com/auth/sign-up?invite=preview' },
+  role: { group: 'team', sample: 'Technician' },
+  invite_expires: { group: 'team', sample: '16 Sep 2026' },
 } as const satisfies Record<string, TagSpec>
 
 export type EmailTag = keyof typeof TAGS
@@ -68,6 +79,7 @@ export const TAG_GROUPS: readonly TagGroup[] = [
   'document',
   'message',
   'portal',
+  'team',
 ]
 
 /**

+ 2 - 0
src/features/team/Actions/resendInvitation.ts

@@ -48,6 +48,8 @@ export async function resendInvitation(input: unknown) {
         email: invitation.email,
         roleLabel: invitation.customRole?.name || invitation.role,
         token,
+        invitedById: invitation.invitedById,
+        expiresAt,
       })
 
       revalidatePath('/settings/team')

+ 23 - 29
src/features/team/Lib/createInvitation.ts

@@ -1,7 +1,6 @@
 import { randomUUID } from 'crypto'
+import { sendTemplatedMail } from '@/features/email/Lib/sendTemplatedMail'
 import { db } from '@/lib/db'
-import { sendOrgMail, getOrgFromAddress } from '@/lib/email'
-import { escapeHtml } from '@/features/email/Render/escape'
 import type { InvitableRole } from './invitationRules'
 
 export type CreateInvitationInput = {
@@ -69,6 +68,8 @@ export async function createAndSendInvitation(input: CreateInvitationInput) {
       email,
       roleLabel: customRoleName || role,
       token,
+      invitedById,
+      expiresAt,
     })
   } catch {
     // Roll back the invitation record so the admin can retry.
@@ -85,38 +86,31 @@ export type InvitationMailInput = {
   email: string
   roleLabel: string
   token: string
+  /** Whoever is inviting; the template can sign off with their name. */
+  invitedById?: string | null
+  expiresAt?: Date | null
 }
 
-/** The sign-up link, mailed from the workshop's own provider. */
+/**
+ * The sign-up link, mailed from the workshop's own provider through the
+ * workshop's template for invitations, so the wording and look are the
+ * workshop's to change like every other mail it sends.
+ */
 export async function sendInvitationMail(input: InvitationMailInput): Promise<void> {
-  const { organizationId, organizationName, email, roleLabel, token } = input
-  const from = await getOrgFromAddress(organizationId)
+  const { organizationId, email, roleLabel, token, invitedById, expiresAt } = input
   const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
-  const signupUrl = `${baseUrl}/auth/sign-up?invite=${token}`
-  const safeOrg = escapeHtml(organizationName)
-  const safeRole = escapeHtml(roleLabel)
+  const inviter = invitedById
+    ? await db.user.findUnique({ where: { id: invitedById }, select: { name: true } })
+    : null
 
-  await sendOrgMail(organizationId, {
-    from,
+  await sendTemplatedMail(organizationId, {
+    kind: 'team_invitation',
     to: email,
-    subject: `You've been invited to join ${organizationName} on Torqvoice`,
-    html: `
-          <div style="font-family: sans-serif; max-width: 480px; margin: 0 auto;">
-            <h2>Team Invitation</h2>
-            <p>You've been invited to join <strong>${safeOrg}</strong> on Torqvoice as a <strong>${safeRole}</strong>.</p>
-            <p>Click the button below to create your account and join the team:</p>
-            <div style="margin: 24px 0;">
-              <a href="${signupUrl}" style="display: inline-block; padding: 12px 24px; background-color: #171717; color: #ffffff; text-decoration: none; border-radius: 8px; font-weight: 500;">
-                Accept Invitation
-              </a>
-            </div>
-            <p style="color: #6b7280; font-size: 14px;">This invitation expires in 7 days.</p>
-            <hr style="border: none; border-top: 1px solid #e5e7eb; margin: 16px 0;" />
-            <p style="color: #6b7280; font-size: 12px;">
-              If the button doesn't work, copy and paste this URL into your browser:<br/>
-              <a href="${signupUrl}" style="color: #6b7280;">${signupUrl}</a>
-            </p>
-          </div>
-        `,
+    context: {
+      inviteLink: `${baseUrl}/auth/sign-up?invite=${token}`,
+      role: roleLabel,
+      expiresAt: expiresAt ?? null,
+      currentUser: inviter?.name ?? null,
+    },
   })
 }