Skip to content

Commit

Permalink
Merge branch 'main' into fixes
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/client/src/app/+state/player-events/actions/register-for-event.action.ts
#	src/client/src/app/+state/player-events/player-events.reducer.ts
#	src/client/src/app/components/player-events/player-event-details/player-event-details.component.html
#	src/client/src/app/components/player-events/player-event-details/player-event-details.component.ts
  • Loading branch information
MaSch0212 committed Jun 9, 2024
2 parents 95c1f47 + 8d4612a commit af9cf32
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 111 deletions.
10 changes: 0 additions & 10 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,3 @@ jobs:
id: push_docker
run: pnpm docker:push
if: github.ref == 'refs/heads/main'

- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: "Minigolffreitag"
slot-name: "production"
publish-profile: ${{ secrets.AzureAppService_PublishProfile_4d5a9096408d4948a5453808899f123a }}
images: "masch0212/minigolf-friday:${{ steps.push_docker.outputs.docker_tag }}"
if: github.ref == 'refs/heads/main'
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
},

"typescript.preferences.importModuleSpecifier": "shortest",
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.tsdk": "src/client/node_modules/typescript/lib",
"[csharp]": {
"editor.defaultFormatter": "csharpier.csharpier-vscode"
},
"editor.rulers": [100],

"tailwindCSS.rootFontSize": 14,
"tailwindCSS.classAttributes": ["class", "className", "ngClass", "styleClass"],
"tailwindCSS.experimental.configFile": "client/tailwind.config.js",
"tailwindCSS.experimental.configFile": "src/client/tailwind.config.js",
"css.customData": [".vscode/tailwind.json"],
"task.autoDetect": "off",
"[xml]": {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { inject } from '@angular/core';
import { concatLatestFrom } from '@ngrx/effects';
import { on, Store } from '@ngrx/store';
import { produce } from 'immer';
import { switchMap } from 'rxjs';

import { ApiEventTimeslotRegistration } from '../../../api/models';
import { EventsService } from '../../../api/services';
import { PlayerEvent } from '../../../models/parsed-models';
import { createHttpAction, handleHttpAction, onHttpAction, toHttpAction } from '../../action-state';
import { createFunctionalEffect } from '../../functional-effect';
import { Effects, Reducers } from '../../utils';
import { PLAYER_EVENTS_ACTION_SCOPE } from '../consts';
import { selectPlayerEvent, selectPlayerEventsActionState } from '../player-events.selectors';
import { PlayerEventsFeatureState, playerEventEntityAdapter } from '../player-events.state';

export const updateEventRegistrationAction = createHttpAction<{
eventId: string;
timeslotId: string;
isRegistered?: boolean;
fallbackTimeslotId?: string | null;
}>()(PLAYER_EVENTS_ACTION_SCOPE, 'Update Event Registration');

export const updateEventRegistrationReducers: Reducers<PlayerEventsFeatureState> = [
on(updateEventRegistrationAction.success, (state, { props }) =>
playerEventEntityAdapter.mapOne(
{
id: props.eventId,
map: produce(draft => {
const timeslot = draft.timeslots.find(t => t.id === props.timeslotId);
if (timeslot) {
if (props.isRegistered !== undefined) {
timeslot.isRegistered = props.isRegistered;
}
if (props.fallbackTimeslotId !== undefined) {
timeslot.chosenFallbackTimeslotId = props.fallbackTimeslotId;
}
}
}),
},
state
)
),
handleHttpAction('register', updateEventRegistrationAction),
];

export const updateEventRegistrationEffects: Effects = {
updateEventRegistration$: createFunctionalEffect.dispatching(
(store = inject(Store), api = inject(EventsService)) =>
onHttpAction(updateEventRegistrationAction, selectPlayerEventsActionState('register')).pipe(
concatLatestFrom(({ props }) => store.select(selectPlayerEvent(props.eventId))),
switchMap(([{ props }, currentEvent]) =>
toHttpAction(
updatePlayerEventRegistrations(api, props, currentEvent),
updateEventRegistrationAction,
props
)
)
)
),
};

async function updatePlayerEventRegistrations(
api: EventsService,
props: ReturnType<typeof updateEventRegistrationAction>['props'],
currentTimeslot: PlayerEvent | undefined
) {
if (!currentTimeslot) return updateEventRegistrationAction.error(props, 'Event not found');

let registrations: ApiEventTimeslotRegistration[] = currentTimeslot.timeslots
.filter(t => t.isRegistered)
.map(t => ({
timeslotId: t.id,
fallbackTimeslotId: t.chosenFallbackTimeslotId,
}));

let timeslotRegistration = registrations.find(r => r.timeslotId === props.timeslotId);
if (props.isRegistered === true && !timeslotRegistration) {
timeslotRegistration = {
timeslotId: props.timeslotId,
fallbackTimeslotId: props.fallbackTimeslotId,
};
registrations.push(timeslotRegistration);
} else if (props.isRegistered === false && timeslotRegistration) {
registrations = registrations.filter(r => r.timeslotId !== props.timeslotId);
timeslotRegistration = undefined;
}

if (timeslotRegistration && props.fallbackTimeslotId !== undefined) {
timeslotRegistration.fallbackTimeslotId = props.fallbackTimeslotId;
}

const response = await api.updatePlayerEventRegistrations({
eventId: props.eventId,
body: { timeslotRegistrations: registrations },
});
return response.ok
? updateEventRegistrationAction.success(props, undefined)
: updateEventRegistrationAction.error(props, response);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { loadPlayerEventAction } from './actions/load-player-event.action';
export { loadPlayerEventsAction } from './actions/load-player-events.action';
export { registerForEventAction } from './actions/register-for-event.action';
export { updateEventRegistrationAction } from './actions/update-event-registration.action';
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { loadPlayerEventEffects } from './actions/load-player-event.action';
import { loadPlayerEventsEffects } from './actions/load-player-events.action';
import { registerForEventEffects } from './actions/register-for-event.action';
import { updateEventRegistrationEffects } from './actions/update-event-registration.action';
import { Effects } from '../utils';

export const PlayerEventsFeatureEffects: Effects[] = [
loadPlayerEventsEffects,
loadPlayerEventEffects,
registerForEventEffects,
updateEventRegistrationEffects,
];
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { produce } from 'immer';

import { loadPlayerEventReducers } from './actions/load-player-event.action';
import { loadPlayerEventsReducers } from './actions/load-player-events.action';
import { registerForEventReducers } from './actions/register-for-event.action';
import { updateEventRegistrationReducers } from './actions/update-event-registration.action';
import {
PlayerEventsFeatureState,
initialPlayerEventsFeatureState,
Expand All @@ -23,7 +23,7 @@ export const playerEventsReducer = createReducer<PlayerEventsFeatureState>(

...loadPlayerEventsReducers,
...loadPlayerEventReducers,
...registerForEventReducers,
...updateEventRegistrationReducers,

on(addEventAction.success, (state, { response }) =>
state.actionStates.load.state === 'none'
Expand Down
76 changes: 76 additions & 0 deletions src/client/src/app/components/+common/fading-message.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
ChangeDetectionStrategy,
Component,
effect,
HostBinding,
input,
OnDestroy,
signal,
untracked,
} from '@angular/core';

@Component({
standalone: true,
selector: 'app-fading-message',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<ng-content></ng-content>`,
styles: `
:host {
display: block;
opacity: 0;
transition-property: opacity;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: var(--fm-fade-out-duration);
&.show {
opacity: 1;
transition-duration: var(--fm-fade-in-duration);
}
}
`,
})
export class FadingMessageComponent implements OnDestroy {
private _lastTimeout?: ReturnType<typeof setTimeout>;
private readonly _isShowing = signal(false);

public readonly fadeInDuration = input<number>(150);
public readonly fadeOutDuration = input<number>(3000);
public readonly showTrigger = input<boolean | null | undefined>();

@HostBinding('style.--fm-fade-in-duration')
protected get fadeInDurationValue() {
return `${this.fadeInDuration()}ms`;
}

@HostBinding('style.--fm-fade-out-duration')
protected get fadeOutDurationValue() {
return `${this.fadeOutDuration()}ms`;
}

@HostBinding('class.show')
protected get hasShowClass() {
return this._isShowing();
}

constructor() {
effect(
() => {
if (this.showTrigger()) {
untracked(() => this.show());
}
},
{ allowSignalWrites: true }
);
}

public show() {
if (this._isShowing()) return;
this._isShowing.set(true);

this._lastTimeout = setTimeout(() => this._isShowing.set(false), this.fadeInDuration());
}

public ngOnDestroy(): void {
clearTimeout(this._lastTimeout);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,34 @@

@if (canRegister() || !event.isStarted) {
<h2 class="m-0 pt-4">{{ translations.playerEvents_registrations() }}</h2>
@for (timeslot of timeslots(); track timeslot.id; let index = $index) {
@for (timeslot of timeslots(); track timeslot.id) {
<p-card>
<div class="flex flex-col gap-4">
<div class="flex flex-row items-center gap-4">
<ng-container
*ngTemplateOutlet="timeslotTemplate; context: { $implicit: timeslot }"
></ng-container>
<div class="grow"></div>
<p-inputSwitch
class="-my-4"
[disabled]="
!canRegister() || isChanginRegistration() || !canRegisterForTimeslot(timeslot)
"
[ngModel]="timeslot.isRegistered"
(ngModelChange)="setTimeslotRegistration(timeslot, $event)"
[resetNgModel]="resetNgModel"
/>
<div class="relative -my-4">
<p-inputSwitch
class="flex"
[disabled]="
!canRegister() ||
isChanginRegistration() ||
!canRegisterForTimeslot(timeslot)
"
[ngModel]="timeslot.isRegistered"
(ngModelChange)="setTimeslotRegistration(timeslot, $event)"
[resetNgModel]="resetNgModel"
/>
<app-fading-message
class="pointer-events-none absolute top-1/2 -translate-x-[calc(100%+8px)] -translate-y-1/2 truncate rounded bg-green-900 px-4 py-2 text-green-200"
[showTrigger]="timeslotSaveStates()[$index] | async"
>
<span class="i-[mdi--check]"></span>
{{ translations.shared_saved() }}
</app-fading-message>
</div>
</div>
@if (timeslot.isRegistered && timeslot.isFallbackAllowed) {
<div class="flex flex-row items-center">
Expand Down
Loading

0 comments on commit af9cf32

Please sign in to comment.