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

Mmc room groups DO NOT MERGE - JUST FOR DISCUSSIONS #240

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .github/workflows/docker-build-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- 'main'
- 'mmc-room-groups'
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'

Expand Down Expand Up @@ -41,7 +42,7 @@ jobs:
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASS: ${{ secrets.GITHUB_TOKEN }}

- name: Docker build and push 'latest' image
- name: Docker build and push 'latest-mmc' image
if: startsWith(github.ref, 'refs/heads/')
run: >
TAG_ARGS=$(echo -n "$IMAGE_TAGS" | sed -r "s_([^ :/]+)_ --tag $REGISTRY/$IMAGE_NAME:\1 _g") &&
Expand All @@ -56,7 +57,7 @@ jobs:
env:
REGISTRY: 'ghcr.io'
IMAGE_NAME: ${{ github.repository }}
IMAGE_TAGS: latest
IMAGE_TAGS: latest-mmc
FULL_REPO_URL: "https://github.com/${{ github.repository }}"
COMMIT_HASH: ${{ github.sha }}

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,13 @@ scp public.tgz [email protected]:projects/
ssh [email protected] -t "bash -l -c 'scripts/update-app.sh'"
rm -f public.tgz
```

### other commands

```
# run the typescript compiler to check for type errors
npm run tsc

# run the linter to check for warnings and errors
npm run lint
```
5 changes: 5 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ exports.onCreatePage = async ({ page, actions }) => {
page.matchPath = "/hotel-booking/*"
createPage(page)
}

if (page.path.match(/^\/room-share/)) {
page.matchPath = "/room-share/*"
createPage(page)
}
}

exports.onCreateWebpackConfig = ({ actions }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/apis/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ export class LoginRequiredError extends Error {
}
}

export interface ErrorDto<ErrorMessage extends string> {
export interface ErrorDto<ErrorMessageEnum extends string> {
// The time at which the error occurred.
readonly timestamp: string // 2006-01-02T15:04:05+07:00

// An internal trace id assigned to the error. Used to find logs associated with errors across our services. Display to the user as something to communicate to us with inquiries about the error.
readonly requestid: string // a8b7c6d5

// A keyed description of the error. We do not write human-readable text here because the user interface will be multi-language.
readonly message: ErrorMessage // attendee.owned.notfound or similar
readonly message: ErrorMessageEnum // attendee.owned.notfound or similar

// Optional additional details about the error. If available, will usually contain English language technobabble.
readonly details: Readonly<Record<string, readonly string[]>>
Expand Down
468 changes: 468 additions & 0 deletions src/apis/roomsrv.ts

Large diffs are not rendered by default.

44 changes: 39 additions & 5 deletions src/components/funnels/funnels/register/steps/summary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Localized, useLocalization } from '@fluent/react'
import WithInvoiceRegisterFunnelLayout from '~/components/funnels/funnels/register/layout/form/with-invoice'
import type { ReadonlyRouteComponentProps } from '~/util/readonly-types'
import styled from '@emotion/styled'
import { useAppSelector } from '~/hooks/redux'
import type { RegistrationStatus } from '~/state/models/register'
Expand All @@ -12,17 +11,22 @@
import { useFunnelForm } from '~/hooks/funnels/form'
import { Checkbox, ErrorMessage, Form } from '@eurofurence/reg-component-library'
import config from '~/config'
import { getRoomGroup } from '~/state/selectors/room-sharing'
import { GroupDto } from '~/apis/roomsrv'

interface PropertyDefinition {
readonly id: string
readonly value: string
readonly wide?: boolean
readonly subvalue?: string
}

interface SectionProps {
readonly id: string
readonly editLink: string
readonly properties: readonly PropertyDefinition[]
readonly editText?: string
readonly showEditLink?: boolean
}

const SectionContainer = styled.section<{ readonly status: RegistrationStatus }>`
Expand Down Expand Up @@ -100,7 +104,6 @@
&:not(:first-child) {
margin-top: 2em;
}
}
`

const TermsForm = styled(Form)`
Expand All @@ -111,29 +114,55 @@
color: ${({ status }) => status === 'cancelled' ? 'var(--color-semantic-error)' : 'unset'};
`

const Section = ({ id: sectionId, editLink, properties }: SectionProps) => {
const Section = ({ id: sectionId, editLink, properties, editText, showEditLink }: SectionProps) => {
const status = useAppSelector(getStatus())!

const editTextStr = editText ?? 'Edit information'
const editTextId = editTextStr === 'Edit information' ? 'register-summary-edit' : `register-summary-${sectionId}-edit`

return <SectionContainer status={status}>
<Localized id={`register-summary-section-${sectionId}-title`}><SectionTitle>{sectionId}</SectionTitle></Localized>
{status === 'cancelled' ? undefined : <Localized id="register-summary-edit"><Link css={editButtonStyle} to={editLink}>Edit information</Link></Localized>}
{status === 'cancelled' || showEditLink === false ? undefined : <Localized id={editTextId}><Link css={editButtonStyle} to={editLink}>{editTextStr}</Link></Localized>}
<PropertyList>
{properties.map(({ id, value, wide = false }) => <Property key={id} wide={wide}>
{properties.map(({ id, value, subvalue, wide = false }) => <Property key={id} wide={wide}>
<Localized id={`register-summary-section-${sectionId}-property-${id}-name`}><PropertyName>{id}</PropertyName></Localized>
<PropertyDescription>{value}</PropertyDescription>
<PropertyName>{subvalue}</PropertyName>
</Property>)}
</PropertyList>
</SectionContainer>
}

// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
const getRoomShareSectionProps = (isAttending: boolean, roomShare: GroupDto | null) => {
if (isAttending && roomShare) {
return [
{ id: 'room-share-group-name', value: roomShare.name },
{ id: 'room-share-members', value: roomShare.members.map(member => member.nickname).join('\n') },
]
}

if (isAttending && !roomShare) {
return [{ id: '', value: 'No group', subvalue: 'You can create or join one on the room sharing page' }]
}

if (!isAttending && !roomShare) {
return [{ id: '', value: 'No group', subvalue: 'Your registration needs to be approved by us first' }]
}
}

// eslint-disable-next-line max-statements
const Summary = (_: ReadonlyRouteComponentProps) => {

Check failure on line 155 in src/components/funnels/funnels/register/steps/summary.tsx

View workflow job for this annotation

GitHub Actions / build-and-test

Cannot find name 'ReadonlyRouteComponentProps'.
const registrationId = useAppSelector(getRegistrationId())!
const personalInfo = useAppSelector(getPersonalInfo())!
const contactInfo = useAppSelector(getContactInfo())!
const optionalInfo = useAppSelector(getOptionalInfo())!
const isEdit = useAppSelector(isEditMode())
const status = useAppSelector(getStatus())!
const isAttendingStatus = ['approved', 'partially-paid', 'paid', 'checked-in'].includes(status)

const roomShare = useAppSelector(getRoomGroup())
const roomShareSectionProps = getRoomShareSectionProps(isAttendingStatus, roomShare)
const locale = useCurrentLocale()
const { l10n } = useLocalization()
const { handleSubmit, register, formState: { errors } } = useFunnelForm('register-summary')
Expand All @@ -155,6 +184,11 @@
<RegistrationId>Badge number: {registrationId}</RegistrationId>
</Localized> : undefined }

{/*TODO: Localize editText*/}
{config.enableRoomshare
? <Section id="room sharing" showEditLink={isAttendingStatus} editLink="/room-share" editText="Set up" properties={roomShareSectionProps}/>

Check failure on line 189 in src/components/funnels/funnels/register/steps/summary.tsx

View workflow job for this annotation

GitHub Actions / build-and-test

Type '{ id: string; value: string; }[] | { id: string; value: string; subvalue: string; }[] | undefined' is not assignable to type 'readonly PropertyDefinition[]'.
: undefined}

<Section id="personal" editLink="/register/personal-info" properties={[
{ id: 'nickname', value: personalInfo.nickname },
{ id: 'full-name', value: `${personalInfo.firstName} ${personalInfo.lastName}` },
Expand Down
11 changes: 11 additions & 0 deletions src/components/funnels/funnels/roomshare/create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ReadonlyRouteComponentProps } from '~/util/readonly-types'

const RoomShareCreate = (_: ReadonlyRouteComponentProps) => {
return (
<div>
{/*<RoomShareCreateForm />*/}
</div>
)
}

export default RoomShareCreate
74 changes: 74 additions & 0 deletions src/components/funnels/funnels/roomshare/home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { ReadonlyRouteComponentProps } from '~/util/readonly-types'
import { useFunnelForm } from '~/hooks/funnels/form'
import { RadioCard, RadioGroup } from '@eurofurence/reg-component-library'
import { Localized } from '@fluent/react'
import { StaticImage } from 'gatsby-plugin-image'
import styled from '@emotion/styled'
import FullWidth from '~/components/funnels/funnels/hotel-booking/layout/form/full-width'
import { useAppSelector } from '~/hooks/redux'
import { getRoomGroup } from '~/state/selectors/room-sharing'

const RoomShareGrid = styled.div`
display: grid;
gap: 20px;

@media not all and (min-width: 600px) {
grid: auto-flow auto / 1fr;
}

@media (min-width: 600px) {
grid: auto-flow 1fr / 1fr 1fr;
}
`

const ConCat = styled.figure`
position: relative;
`

const NoRoomShare = (_: ReadonlyRouteComponentProps) => {
const { register, handleSubmit } = useFunnelForm('room-sharing-create-join')

return (
<FullWidth onNext={handleSubmit}>
<h3>Roomsharing</h3>
<form onSubmit={handleSubmit}>
<RadioGroup name="type">
<RoomShareGrid>
<Localized id="room-share-create-new-group" attrs={{ label: true }}>
<RadioCard label="Create a new group" value="create" {...register('type', { required: true })}>
<ConCat><StaticImage height={400} src="../../../../images/con-cats/room-share/create.png"
alt=""/></ConCat>
</RadioCard>
</Localized>
<Localized id="room-share-join-group" attrs={{ label: true }}>
<RadioCard label="Join an existing group" value="join" {...register('type', { required: true })}>
<ConCat><StaticImage height={400} src="../../../../images/con-cats/room-share/join.png"
alt=""/></ConCat>
</RadioCard>
</Localized>
</RoomShareGrid>
</RadioGroup>
</form>
</FullWidth>
)
}

const RoomShareOptions = () => {
return (
<div>
TODO
</div>
)
}

const RoomShareHome = (_: ReadonlyRouteComponentProps) => {
const roomShare = useAppSelector(getRoomGroup())

if (roomShare) {
return <RoomShareOptions />
} else {
return <NoRoomShare />
}
}

export default RoomShareHome
7 changes: 7 additions & 0 deletions src/components/funnels/funnels/roomshare/join.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { ReadonlyRouteComponentProps } from '~/util/readonly-types'

const RoomShareJoin = (_: ReadonlyRouteComponentProps) => {
return <div>RoomShareJoin</div>
}

export default RoomShareJoin
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const config = checkConfig({
dayTicketEndDate: DateTime.fromISO('2024-09-21', { zone: 'Europe/Berlin' }),
earliestBirthDate: DateTime.fromISO('1901-01-01'),
minimumAge: 18,
enableRoomshare: true, // TODO: For development
allowedCountries: ['AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AC', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG', 'BF', 'BI', 'CV', 'KH', 'CM', 'CA', 'KY', 'CF', 'EA', 'TD', 'CL', 'CN', 'CX', 'CP', 'CC', 'CO', 'KM', 'CG', 'CD', 'CK', 'CR', 'HR', 'CU', 'CW', 'CY', 'CZ', 'CI', 'DK', 'DG', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'SZ', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT', 'HM', 'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL', 'IT', 'JM', 'JP', 'JE', 'JO', 'IC', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', 'LU', 'MO', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX', 'FM', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI', 'NE', 'NG', 'NU', 'NF', 'MK', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF', 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL', 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'SS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TA', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'UM', 'US', 'UY', 'UZ', 'VU', 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW'],
ticketLevels: {
'standard': {
Expand Down Expand Up @@ -253,6 +254,10 @@ const config = checkConfig({
paysrv: {
url: apiPath('/paysrv/api/rest/v1'),
},
roomsrv: {
url: apiPath('/roomsrv/api/rest/v1'),
enable: true,
},
},
websiteLinks: {
// these two links need to be in the footer bar on each page
Expand Down
Binary file added src/images/con-cats/room-share/apply.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/con-cats/room-share/create.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/con-cats/room-share/join.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/con-cats/room-share/kick.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/con-cats/room-share/leave.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/navigation/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import * as ROUTES from './routes'
import { withPrefix } from 'gatsby'
import { useAppSelector } from '~/hooks/redux'
import { isEditMode } from '~/state/selectors/register'
import RoomShareHome from '~/components/funnels/funnels/roomshare/home'
import RoomShareCreate from '~/components/funnels/funnels/roomshare/create'
import RoomShareJoin from '~/components/funnels/funnels/roomshare/join'

export const EFRouter = () =>
<IndexPage />
Expand All @@ -39,3 +42,11 @@ export const HotelBookingRouter = () =>
<AdditionalInfo path={ROUTES.HOTEL_BOOKING_ADDITIONAL_INFO} />
<Email path={ROUTES.HOTEL_BOOKING_EMAIL} />
</Router>

export const RoomShareRouter = () => {
return <Router basepath={withPrefix('/room-share')}>
<RoomShareHome default path={`${ROUTES.REGISTER_ROOM_SHARE_HOME}`} />
<RoomShareCreate path={`${ROUTES.REGISTER_ROOM_SHARE_CREATE}`} />
<RoomShareJoin path={`${ROUTES.REGISTER_ROOM_SHARE_JOIN}`} />
</Router>
}
4 changes: 4 additions & 0 deletions src/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export const REGISTER_TICKET_LEVEL = 'level'
export const REGISTER_PERSONAL = 'personal-info'
export const REGISTER_CONTACT = 'contact-info'
export const REGISTER_OPTIONAL = 'optional-info'
export const REGISTER_ROOM_SHARE = 'room-share'
export const REGISTER_ROOM_SHARE_HOME = 'home'
export const REGISTER_ROOM_SHARE_JOIN = 'join'
export const REGISTER_ROOM_SHARE_CREATE = 'create'
export const REGISTER_SUMMARY = 'summary'
export const REGISTER_THANK_YOU = 'thank-you'

Expand Down
17 changes: 17 additions & 0 deletions src/pages/room-share.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RoomShareRouter } from '~/navigation/router'

import SEO from '~/components/seo'
import { ReadonlyRouteComponentProps } from '~/util/readonly-types'
import Layout from '~/components/layout'

export const Head = () => <SEO title="Room Sharing" />

const RoomSharingPage = (_: ReadonlyRouteComponentProps) => {
return (
<Layout>
<RoomShareRouter />
</Layout>
)
}

export default RoomSharingPage
3 changes: 3 additions & 0 deletions src/state/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ErrorAction } from './errors'
import { FormAction } from './forms'
import { RegisterAction } from './register'
import { NavigationAction } from './navigation'
import { RoomSharingAction } from './room-sharing'

export type { GetAction } from './create-action'

Expand All @@ -14,3 +15,5 @@ export type AnyAppAction =
| FormAction
| RegisterAction
| NavigationAction
| RoomSharingAction
// Add new action types here
7 changes: 7 additions & 0 deletions src/state/actions/room-sharing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createAction } from './create-action'
import { GroupDto } from '~/apis/roomsrv'

export const LoadRoomShareState = createAction<GroupDto | null, '[RoomSharing] Load room share state'>('[RoomSharing] Load room share state')

export type RoomSharingAction
= typeof LoadRoomShareState
2 changes: 2 additions & 0 deletions src/state/epics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import autosave from './autosave'
import register from './register'
import hotelBooking from './hotel-booking'
import navigation from './navigation'
import roomSharing from './room-sharing'

export default combineEpics(
auth,
autosave,
register,
hotelBooking,
navigation,
roomSharing,
)
Loading
Loading