diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 5e5c7ff8..f6faf0cc 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -45,6 +45,7 @@ "dayjs": "^1.11.10", "form-data": "^4.0.0", "hotkeys-js": "^3.11.2", + "html-to-image": "^1.11.11", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "openai-edge": "^1.2.2", @@ -84,6 +85,7 @@ "jest": "^29.7.0", "postcss": "^8.4.24", "postcss-load-config": "^4.0.1", + "qrcode": "^1.5.3", "sass": "^1.64.2", "svelte": "^4.1.2", "svelte-calendar": "^3.1.6", diff --git a/apps/dashboard/src/lib/components/Course/components/People/InvitationModal.svelte b/apps/dashboard/src/lib/components/Course/components/People/InvitationModal.svelte index 34933967..3f0f0bb9 100644 --- a/apps/dashboard/src/lib/components/Course/components/People/InvitationModal.svelte +++ b/apps/dashboard/src/lib/components/Course/components/People/InvitationModal.svelte @@ -1,20 +1,23 @@ - + {$t('course.navItem.people.invite_modal.invite_students')} @@ -187,21 +225,45 @@ - - {$t('course.navItem.people.invite_modal.copy_link')} - - + + + {$t('course.navItem.people.invite_modal.success')} + + + + {$t('course.navItem.people.invite_modal.via_qr')} + + + + + + + + + + + + + + + import type { CurrentOrg } from '$lib/utils/types/org.ts'; + import type { Course } from '$lib/utils/types/index.ts'; + import { isFreePlan } from '$lib/utils/store/org'; + import { qrInviteNodeStore } from './store'; + + let node: any; + + $: qrInviteNodeStore.set(node); + + export let qrImage: string; + export let currentOrg: CurrentOrg; + export let course: Course; + + + + + Scan QR + + + {course.title} + {currentOrg.name} + + + {#if $isFreePlan} + + + ClassroomIO.com + + {/if} + diff --git a/apps/dashboard/src/lib/components/Course/components/People/store.js b/apps/dashboard/src/lib/components/Course/components/People/store.js index 390b4959..c7b637c3 100644 --- a/apps/dashboard/src/lib/components/Course/components/People/store.js +++ b/apps/dashboard/src/lib/components/Course/components/People/store.js @@ -3,3 +3,5 @@ import { writable } from 'svelte/store'; export const deleteMemberModal = writable({ open: false }); + +export const qrInviteNodeStore = writable(null); diff --git a/apps/dashboard/src/lib/utils/translations/en.json b/apps/dashboard/src/lib/utils/translations/en.json index 4cc53120..ae1918f3 100644 --- a/apps/dashboard/src/lib/utils/translations/en.json +++ b/apps/dashboard/src/lib/utils/translations/en.json @@ -803,6 +803,9 @@ "go_to": "go to organization settings", "invite_students": "Invite Students", "via_link": "You can invite students via an invite link", + "via_qr": "You can invite students via QR", + "download_qr": "Download QR code", + "qr_downloading_snackbar": "QR code generated successfully, please wait while it downloads", "copy_link": "Copy link", "success": "Copied Successfully", "finish": "Finish" diff --git a/apps/dashboard/static/logo.svg b/apps/dashboard/static/logo.svg new file mode 100644 index 00000000..0ca32c74 --- /dev/null +++ b/apps/dashboard/static/logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf9c9b59..075a0dcd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -237,6 +237,9 @@ importers: hotkeys-js: specifier: ^3.11.2 version: 3.11.2 + html-to-image: + specifier: ^1.11.11 + version: 1.11.11 js-yaml: specifier: ^4.1.0 version: 4.1.0 @@ -349,6 +352,9 @@ importers: postcss-load-config: specifier: ^4.0.1 version: 4.0.1(postcss@8.4.24)(ts-node@10.9.2) + qrcode: + specifier: ^1.5.3 + version: 1.5.3 sass: specifier: ^1.64.2 version: 1.64.2 @@ -7680,6 +7686,14 @@ packages: execa: 0.8.0 dev: false + /cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: true + /cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -8870,6 +8884,10 @@ packages: engines: {node: '>=0.3.1'} dev: false + /dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -9002,6 +9020,10 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + /encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: true + /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -14017,6 +14039,11 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + /pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: true + /postcss-import@15.1.0(postcss@8.4.32): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -14475,6 +14502,17 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} dev: true + /qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: true + /qs@6.10.4: resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} engines: {node: '>=0.6'} @@ -14867,6 +14905,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true @@ -15126,7 +15168,6 @@ packages: /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: false /set-cookie-parser@2.6.0: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} @@ -17219,6 +17260,10 @@ packages: is-weakset: 2.0.2 dev: true + /which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: true + /which-typed-array@1.1.13: resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} engines: {node: '>= 0.4'} @@ -17329,6 +17374,10 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + /y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: true + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -17357,6 +17406,14 @@ packages: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} + /yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: true + /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -17366,6 +17423,23 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + /yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: true + /yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'}
{$t('course.navItem.people.invite_modal.invite_students')} @@ -187,21 +225,45 @@
{course.title}
{currentOrg.name}