Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Journey with Data Wallet #3142

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7304745
feat(data-wallet): reenable user journey
hugotiburtino Nov 2, 2023
d257a69
refactor(user-journey): remove unimportant code that wont work anyway
hugotiburtino Nov 2, 2023
3400b24
refactor(user-journey): fix import errors and remove unnecesary file
hugotiburtino Nov 2, 2023
4b67139
refactor(user-journey): remove unnecessary file
hugotiburtino Nov 3, 2023
a91f304
Merge branch 'staging' into lenabi-user-journey
hugotiburtino Nov 29, 2023
aa2be96
refactor(wallet): match name of wallet app
hugotiburtino Nov 30, 2023
44ff27c
refactor(wallet): fix syntax
hugotiburtino Dec 1, 2023
2e57373
feat(user-journey): redirect user to willkommen after login
hugotiburtino Dec 1, 2023
e542183
refactor(user-journey): tidy up
hugotiburtino Dec 1, 2023
5204253
feat(user-journey): redirect to willkommen page also in SSO
hugotiburtino Dec 4, 2023
4cd90b5
Revert "feat(user-journey): redirect to willkommen page also in SSO"
hugotiburtino Dec 5, 2023
0725e1d
fix(user-journey): try another way to redirect to willkommen after sso
hugotiburtino Dec 5, 2023
1dd9a92
fix(user-journey): now really redirect to willkommen after sso login
hugotiburtino Dec 5, 2023
a3146d7
refactor(user-jouney): remove dead code
hugotiburtino Dec 5, 2023
34f176b
trigger rebuild
elbotho Dec 6, 2023
4d92ea8
Merge branch 'staging' into lenabi-user-journey
Entkenntnis Mar 13, 2024
70d9217
fix: lint
Entkenntnis Mar 13, 2024
f684549
Merge branch 'staging' into lenabi-user-journey
elbotho Mar 25, 2024
187ff1a
Merge branch 'staging' into lenabi-user-journey
elbotho Apr 15, 2024
7ad9c35
Merge branch 'staging' into lenabi-user-journey
elbotho Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/api/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export const endpointBaseUrl =
: `https://api.${serloDomain}`

export const endpoint = `${endpointBaseUrl}/graphql`
export const endpointEnmeshed = `${endpointBaseUrl}/enmeshed`
10 changes: 9 additions & 1 deletion src/components/content/entity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { Router } from 'next/router'
import { useState, MouseEvent } from 'react'

import { MockupGaps } from './exercises/mockup-gaps'
import { HSpace } from './h-space'
import { Link } from './link'
import { FaIcon } from '../fa-icon'
Expand Down Expand Up @@ -51,6 +52,9 @@ export function Entity({ data }: EntityProps) {
})

const { strings } = useInstanceData()

const isMockupCoursePage = data.id === 244386

return wrapWithSchema(
<>
{renderCourseNavigation()}
Expand All @@ -59,7 +63,11 @@ export function Entity({ data }: EntityProps) {
{renderStyledH1()}
{renderUserTools({ aboveContent: true })}
<div className="min-h-1/4" key={data.id}>
{data.content && renderContent(data.content)}
{isMockupCoursePage ? (
hugotiburtino marked this conversation as resolved.
Show resolved Hide resolved
<MockupGaps />
) : (
data.content && renderContent(data.content)
)}
</div>
{renderCourseFooter()}
<HSpace amount={20} />
Expand Down
129 changes: 129 additions & 0 deletions src/components/content/exercises/mockup-gaps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { faSave } from '@fortawesome/free-regular-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import nProgress from 'nprogress'
import { useState } from 'react'

import { endpointEnmeshed } from '@/api/endpoint'
import { showToastNotice } from '@/helper/show-toast-notice'
import { triggerSentry } from '@/helper/trigger-sentry'
import { GapEx, Gappy } from '@/pages/___gaps'

export function MockupGaps() {
const [showWalletNotice, setShowWalletNotice] = useState(false)
const [success, setSuccess] = useState(false)

function onFeedbackHandler(success: boolean) {
setShowWalletNotice(true)
setSuccess(success)
}

/*
Wähle die richtigen Begriffe für die Lücken.
Das [logistische] Wachstum verläuft in drei Phasen:
Zunächst wächst die Größe [exponentiell] und der Graph steigt [stark].
In der zweiten Phase ist das Wachstum [annähernd linear]. In diesem Bereich liegt auch [der Wendepunkt].
Der Graph [steigt] in der dritten Phase [schwach]. Das Wachstum ist [beschränkt].
[die Asymptote] [kubisch] [fällt] [logarithmische]
*/

return (
<>
<GapEx
choices={[
'logistische',
'exponentiell',
'stark',
'annähernd linear',
'der Wendepunkt',
'steigt',
'schwach',
'beschränkt',
'die Asymptote',
'kubisch',
'fällt',
'logarithmische',
]}
count={8}
onFeedback={onFeedbackHandler}
>
<div className="serlo-p mb-block leading-relaxed">
<p className="mb-4">
<b>Wähle die richtigen Begriffe für die Lücken.</b>
</p>
<p className="mb-4">
Das <Gappy index={0} /> Wachstum verläuft in drei Phasen:
</p>
<p className="mb-4">
Zunächst wächst die Größe <Gappy index={1} /> und der Graph steigt{' '}
<Gappy index={2} />.
</p>
<p className="mb-4">
In der zweiten Phase ist das Wachstum <Gappy index={3} />.<br /> In
diesem Bereich liegt auch <Gappy index={4} />.
</p>
<p className="mb-4">
Der Graph <Gappy index={5} /> in der dritten Phase{' '}
<Gappy index={6} />
. Das Wachstum ist <Gappy index={7} />.
</p>
</div>
</GapEx>
{showWalletNotice ? (
<div className="mx-side my-20 rounded-xl bg-brand-100 p-side text-center">
{success
? 'Super, du hast den Kurs erfolgreich durchgearbeitet! '
: 'Yeah, du hast den Kurs durchgearbeitet. '}
<>
Du kannst deinen Lernfortschritt jetzt speichern.
<br />
{!success && 'Oder du probierst dich noch mal an der Übung'}
<br />
<button
className="serlo-make-interactive-green serlo-button m-auto mt-2 text-center"
onClick={saveLearningProgress}
>
<FontAwesomeIcon icon={faSave} /> In deiner Wallet speichern
</button>
</>
</div>
) : null}
</>
)

function saveLearningProgress() {
const sessionId = sessionStorage.getItem('sessionId')
const name = 'LernstandMathe'
const value = encodeURIComponent('✓ Logistisches Wachstum')

if (!sessionId) return

nProgress.start()

fetch(
`${endpointEnmeshed}/attributes?name=${name}&value=${value}&sessionId=${sessionId}`,
{ method: 'POST' }
)
.then((res) => res.json())
.then(() => {
setTimeout(() => {
nProgress.done()
showToastNotice(
'👌 Lernstand wurde erfolgreich an deine Wallet gesendet',
'success',
6000
)
setShowWalletNotice(false)
}, 540)
})
.catch((e) => {
// eslint-disable-next-line no-console
console.log(JSON.stringify(e))
triggerSentry({
message: `Error in User-Journey: Saving Attribute: ${JSON.stringify(
e
)}`,
})
setShowWalletNotice(false)
})
}
}
166 changes: 166 additions & 0 deletions src/components/pages/data-wallet-journey.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import clsx from 'clsx'
import { SetStateAction, useState } from 'react'

import { HeadTags } from '../head-tags'
import { PartnerList } from '../landing/rework/partner-list'
import { Logo } from '../navigation/header/logo'
import { endpointEnmeshed } from '@/api/endpoint'
import { LoadingSpinner } from '@/components/loading/loading-spinner'
import { triggerSentry } from '@/helper/trigger-sentry'

export function createQRCode(
stateSetter: (value: SetStateAction<string>) => void
) {
stateSetter('loading')
fetch(`${endpointEnmeshed}/init`, {
method: 'POST',
headers: {
Accept: 'image/png',
},
})
.then((res) => res.blob())
.then((res) => {
const urlCreator = window.URL || window.webkitURL
stateSetter(urlCreator.createObjectURL(res))
// TODO: When the workflow has been defined in the future we should revoke the object URL when done with:

Check warning on line 25 in src/components/pages/data-wallet-journey.tsx

View workflow job for this annotation

GitHub Actions / eslint

Unexpected 'todo' comment: 'TODO: When the workflow has been defined...'
// urlCreator.revokeObjectUrl(qrCode)
})
.catch((e) => {
// eslint-disable-next-line no-console
console.log(JSON.stringify(e))

triggerSentry({
message: `error while creating qr code: ${JSON.stringify(e)}`,
})
})
}

export function DataWallet() {
const [qrCode, setQrCode] = useState('')

return (
<>
<HeadTags data={{ title: 'Data Wallet – Serlo.org' }} />
<header className="bg-brand-100 px-side pt-12 sm:text-center">
<div className="pb-6">
<Logo />
</div>
</header>

<section
className={clsx(
'serlo-responsive-margin mb-20 mt-5',
'md:mt-12 md:px-8 lg:block'
)}
>
<div className="max-w-xl text-lg sm:mx-auto">
<h1 className="serlo-h1 mb-5 mt-16 text-brand">
Deine Daten. Deine Rechte.
</h1>
<p className="serlo-p">
Wir gehen verantwortungsvoll mit deinen Daten um. Serlo ist dafür
Projektpartner des Bildungsraums Digital (BIRD). BIRD setzt eine
sogenannte „Data Wallet“ ein, die es dir ermöglicht, deine Daten
sicher und direkt mit uns zu teilen.
</p>
<p className="serlo-p">
Die Data Wallet ist auf deinem Smartphone, dort sind deine Daten
sicher aufgehoben. Um Serlo dein Vertrauen zu schenken, ist eine
einmalige Einrichtung erforderlich:
</p>
<ol className="serlo-ol mb-4 text-lg">
<li>
Lade dir die{' '}
<a
className="serlo-link font-bold"
href="https://enmeshed.eu/use/basics"
target="_blank"
rel="noreferrer"
>
Enmeshed App
</a>{' '}
auf dein Smartphone.
</li>
<li>
Erstelle einen{' '}
<a
className="serlo-link cursor-pointer font-bold"
onClick={() => createQRCode(setQrCode)}
>
QR-Code
</a>
.
{qrCode &&
((qrCode === 'loading' && <LoadingSpinner noText />) || (
<img src={qrCode} />

Check warning on line 95 in src/components/pages/data-wallet-journey.tsx

View workflow job for this annotation

GitHub Actions / eslint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
))}
</li>
<li>
Lege in deiner Enmeshed App ein neues Profil an und füge Serlo als
Kontakt hinzu, indem du den QR-Code scannst.
</li>
<li>
Sobald der Kontakt verifiziert wurde, erhältst du innerhalb
weniger Minuten eine Benachrichtigung in deiner Enmeshed App.
</li>
</ol>
<p className="serlo-p mt-16">
Sollten dabei Probleme auftauchen,{' '}
<a

Check warning on line 109 in src/components/pages/data-wallet-journey.tsx

View workflow job for this annotation

GitHub Actions / eslint

Do not use an `<a>` element to navigate to `/kontakt/`. Use `<Link />` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages
className="serlo-link font-bold"
href="/kontakt#technischersupport"
>
kontaktiere
</a>{' '}
uns gern.
</p>
<noscript>Bitte Javascript aktivieren</noscript>
</div>
</section>

<footer className="partner serlo-responsive-padding pb-1 text-center font-bold">
<h2 className="pb-12 pt-16 text-center font-bold">
Partner und Unterstützer
</h2>
<PartnerList />
<nav>
<a
href="https://de.serlo.org/serlo"
target="_blank"
rel="noreferrer"
className="serlo-link"
>
Über Serlo
</a>
{' • '}
<a
href="https://de.serlo.org/privacy"
target="_blank"
rel="noreferrer"
className="serlo-link"
>
Datenschutz
</a>
{' • '}
<a
href="https://de.serlo.org/imprint"
target="_blank"
rel="noreferrer"
className="serlo-link"
>
Impressum
</a>
</nav>
<style jsx>
{`
.partner {
background: url('/_assets/img/landing/about-container.svg');
border-bottom: 2rem solid #ffefda;
background-size: cover;
}
`}
</style>
</footer>
</>
)
}
Loading
Loading