feat(course): auto-enrol button for paid course join requests (#769)
* feat(course): add auto-enrol flow for paid course join requests - Extend teacher buy-request email with manual access steps and an Auto Enrol this Student button - Link teachers to the course People page with grantAccess query param - Add grant-access modal that sends the same org audience invite used by the Invite new students flow Co-authored-by: Rotimi Best <[email protected]> * fix(i18n): translate grant access modal strings Replace English placeholders copied into non-en locale files with proper translations for each supported language. Co-authored-by: Rotimi Best <[email protected]> * fix(email): shorten auto-enrol button label per review Co-authored-by: Rotimi Best <[email protected]> * fix(email): use American spelling Enroll in auto-enroll CTA Co-authored-by: Rotimi Best <[email protected]> * fix(i18n): localize Danish grant-access send invite label Co-authored-by: Rotimi Best <[email protected]> --------- Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
co-authored by
Rotimi Best
parent
634ffeab0f
commit
6c3a982daf
@@ -0,0 +1,91 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import * as Dialog from '@cio/ui/base/dialog';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { courseApi } from '$features/course/api';
|
||||
import { orgApi } from '$features/org/api/org.svelte';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { isStudentLimitReached } from '$lib/utils/store/org';
|
||||
import { UpgradeBanner } from '$features/ui';
|
||||
|
||||
const GRANT_ACCESS_PARAM = 'grantAccess';
|
||||
|
||||
let courseId = $derived(courseApi.course?.id ?? '');
|
||||
const studentEmail = $derived(new URLSearchParams(page.url.search).get(GRANT_ACCESS_PARAM)?.trim() ?? '');
|
||||
const isOpen = $derived(Boolean(studentEmail));
|
||||
|
||||
let isSubmitting = $state(false);
|
||||
|
||||
function closeModal() {
|
||||
const nextParams = new URLSearchParams(page.url.search);
|
||||
nextParams.delete(GRANT_ACCESS_PARAM);
|
||||
const query = nextParams.toString();
|
||||
|
||||
goto(resolve(`${page.url.pathname}${query ? `?${query}` : ''}`, {}));
|
||||
}
|
||||
|
||||
async function handleSendInvite() {
|
||||
if (!courseId || !studentEmail || $isStudentLimitReached) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSubmitting = true;
|
||||
|
||||
try {
|
||||
const response = await orgApi.importAudienceMembers({
|
||||
recipientCsv: studentEmail,
|
||||
courseIds: [courseId],
|
||||
sendEmail: true
|
||||
});
|
||||
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
await courseApi.refreshCourse(courseId, $profile.id);
|
||||
closeModal();
|
||||
} finally {
|
||||
isSubmitting = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) closeModal();
|
||||
}}
|
||||
>
|
||||
<Dialog.Content class="max-w-md">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{$t('course.navItem.people.grant_access_modal.title')}</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
{$t('course.navItem.people.grant_access_modal.description', { email: studentEmail })}
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
{#if $isStudentLimitReached}
|
||||
<UpgradeBanner removeParams={[GRANT_ACCESS_PARAM]}>
|
||||
{$t('course.navItem.people.invite_modal.student_limit_reached')}
|
||||
</UpgradeBanner>
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button type="button" variant="outline" onclick={closeModal} disabled={isSubmitting}>
|
||||
{$t('course.navItem.people.grant_access_modal.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onclick={handleSendInvite}
|
||||
loading={isSubmitting}
|
||||
disabled={$isStudentLimitReached || !studentEmail}
|
||||
>
|
||||
{$t('course.navItem.people.grant_access_modal.send_invite')}
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -11,6 +11,7 @@
|
||||
import * as Avatar from '@cio/ui/base/avatar';
|
||||
import { ComingSoon, RoleBasedSecurity, UpgradeBanner } from '$features/ui';
|
||||
import InvitationModal from '$features/course/components/people/invitation-modal.svelte';
|
||||
import GrantAccessModal from '$features/course/components/people/grant-access-modal.svelte';
|
||||
import DeleteConfirmation from '$features/course/components/people/delete-confirmation.svelte';
|
||||
import { isStudentLimitReached } from '$lib/utils/store/org';
|
||||
|
||||
@@ -101,6 +102,7 @@
|
||||
</script>
|
||||
|
||||
<InvitationModal />
|
||||
<GrantAccessModal />
|
||||
|
||||
{#if $isStudentLimitReached}
|
||||
<UpgradeBanner className="mb-2">{$t('course.navItem.people.invite_modal.student_limit_reached')}</UpgradeBanner>
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Giv studerende adgang",
|
||||
"description": "Giv {email} adgang til dette kursus. Vi sender en invitationsmail, så vedkommende kan tilslutte sig din organisation og tilmelde sig kurset.",
|
||||
"cancel": "Annuller",
|
||||
"send_invite": "Send invitationen"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Schülerzugang gewähren",
|
||||
"description": "Gewähren Sie {email} Zugang zu diesem Kurs. Wir senden eine Einladungs-E-Mail, damit die Person Ihrer Organisation beitreten und in diesem Kurs eingeschrieben werden kann.",
|
||||
"cancel": "Abbrechen",
|
||||
"send_invite": "Einladung senden"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -3230,6 +3230,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Give student access",
|
||||
"description": "Give {email} access to this course. We'll send them an invite email to join your organization and enroll in this course.",
|
||||
"cancel": "Cancel",
|
||||
"send_invite": "Send invite"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Dar acceso al estudiante",
|
||||
"description": "Da acceso a {email} a este curso. Le enviaremos un correo de invitación para unirse a tu organización e inscribirse en este curso.",
|
||||
"cancel": "Cancelar",
|
||||
"send_invite": "Enviar invitación"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Accorder l'accès à l'étudiant",
|
||||
"description": "Accordez à {email} l'accès à ce cours. Nous lui enverrons un e-mail d'invitation pour rejoindre votre organisation et s'inscrire à ce cours.",
|
||||
"cancel": "Annuler",
|
||||
"send_invite": "Envoyer l'invitation"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "छात्र को एक्सेस दें",
|
||||
"description": "{email} को इस कोर्स का एक्सेस दें। हम उन्हें आपके संगठन में शामिल होने और इस कोर्स में नामांकन के लिए आमंत्रण ईमेल भेजेंगे।",
|
||||
"cancel": "रद्द करें",
|
||||
"send_invite": "निमंत्रण भेजें"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Udostępnij dostęp studentowi",
|
||||
"description": "Przyznaj {email} dostęp do tego kursu. Wyślemy zaproszenie e-mailem, aby dołączył do Twojej organizacji i zapisał się na ten kurs.",
|
||||
"cancel": "Anuluj",
|
||||
"send_invite": "Wyślij zaproszenie"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Conceder acesso ao aluno",
|
||||
"description": "Conceda acesso a {email} a este curso. Enviaremos um e-mail de convite para que a pessoa entre na sua organização e se inscreva neste curso.",
|
||||
"cancel": "Cancelar",
|
||||
"send_invite": "Enviar convite"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Предоставить доступ студенту",
|
||||
"description": "Предоставьте {email} доступ к этому курсу. Мы отправим приглашение по электронной почте, чтобы присоединиться к вашей организации и записаться на курс.",
|
||||
"cancel": "Отмена",
|
||||
"send_invite": "Отправить приглашение"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
@@ -1198,6 +1198,12 @@
|
||||
"no_matching_existing_students": "No organization students match your search.",
|
||||
"notify_existing_students": "Send course access email",
|
||||
"grant_access": "Grant Access",
|
||||
"grant_access_modal": {
|
||||
"title": "Cấp quyền truy cập cho học viên",
|
||||
"description": "Cấp cho {email} quyền truy cập khóa học này. Chúng tôi sẽ gửi email mời để tham gia tổ chức của bạn và đăng ký khóa học.",
|
||||
"cancel": "Hủy",
|
||||
"send_invite": "Gửi lời mời"
|
||||
},
|
||||
"invite_new_students_title": "Invite new students",
|
||||
"invite_new_students_description": "Invite new people into your organization and pre-assign them to this course. They will create an account, accept the invite, and get access.",
|
||||
"invite_new_students": "Invite Students",
|
||||
|
||||
Reference in New Issue
Block a user