diff --git a/src/app/services/waiting-service-judges.service.ts b/src/app/services/waiting-service-judges.service.ts index c91e1b5..64a9f88 100644 --- a/src/app/services/waiting-service-judges.service.ts +++ b/src/app/services/waiting-service-judges.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; -import { db } from 'db'; +import { db, Umpire } from 'db'; import { liveQuery } from 'dexie'; import { from } from 'rxjs'; @@ -21,8 +21,8 @@ export class WaitingServiceJudgesService { /** * Add new umpire to queue with max(order) + 1 */ - async add(serviceJudgeId: number): Promise { - return db.transaction('rw', db.waitingServiceJudges, async () => { + async add(serviceJudgeId: number, toPosition?: number): Promise { + const id = await db.transaction('rw', db.waitingServiceJudges, async () => { const last = await db.waitingServiceJudges.orderBy('order').last(); const nextOrder = last ? last.order + 1 : 1; @@ -32,6 +32,12 @@ export class WaitingServiceJudgesService { order: nextOrder }); }); + + if (toPosition !== undefined) { + await this.moveToPosition(serviceJudgeId, toPosition); + } + + return id; } /** @@ -39,6 +45,8 @@ export class WaitingServiceJudgesService { */ async remove(id: number): Promise { await db.waitingServiceJudges.delete(id); + + await this.reinitOrders(); } async removeByUmpireId(umpireId: number): Promise { @@ -51,7 +59,7 @@ export class WaitingServiceJudgesService { return; } - await db.waitingServiceJudges.delete(item.id); + await this.remove(item.id); } /** @@ -67,4 +75,81 @@ export class WaitingServiceJudgesService { async clear(): Promise { await db.waitingServiceJudges.clear(); } + + async moveToPosition(umpireId: number, newOrder: number): Promise { + await db.transaction('rw', db.waitingServiceJudges, async () => { + const current = await db.waitingServiceJudges + .where('serviceJudgeId') + .equals(umpireId) + .first(); + + if (!current) { + return; + } + + const oldOrder = current.order; + + if (oldOrder === newOrder) { + return; + } + + if (newOrder < oldOrder) { + // Moving up: shift affected records down + + const affected = await db.waitingServiceJudges + .filter( + (item) => + item.order >= newOrder && + item.order < oldOrder && + item.id !== current.id + ) + .toArray(); + + for (const item of affected) { + await db.waitingServiceJudges.update(item.id!, { + order: item.order + 1 + }); + } + } else { + // Moving down: shift affected records up + + const affected = await db.waitingServiceJudges + .filter( + (item) => + item.order > oldOrder && + item.order <= newOrder && + item.id !== current.id + ) + .toArray(); + + for (const item of affected) { + await db.waitingServiceJudges.update(item.id!, { + order: item.order - 1 + }); + } + } + + await db.waitingServiceJudges.update(current.id!, { + order: newOrder + }); + }); + } + + async reinitOrders(): Promise { + await db.transaction('rw', db.waitingServiceJudges, async () => { + const items = await db.waitingServiceJudges.orderBy('order').toArray(); + + for (let i = 0; i < items.length; i++) { + const item = items[i]; + + const expectedOrder = i + 1; + + if (item.order !== expectedOrder) { + await db.waitingServiceJudges.update(item.id!, { + order: expectedOrder + }); + } + } + }); + } } diff --git a/src/app/services/waiting-umpires.service.ts b/src/app/services/waiting-umpires.service.ts index 0f4bff6..c10dcb4 100644 --- a/src/app/services/waiting-umpires.service.ts +++ b/src/app/services/waiting-umpires.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; -import { db } from 'db'; +import { db, Umpire } from 'db'; import { liveQuery } from 'dexie'; import { from } from 'rxjs'; @@ -21,8 +21,8 @@ export class WaitingUmpiresService { /** * Add new umpire to queue with max(order) + 1 */ - async add(umpireId: number): Promise { - return db.transaction('rw', db.waitingUmpires, async () => { + async add(umpireId: number, toPosition?: number): Promise { + const id = await db.transaction('rw', db.waitingUmpires, async () => { const last = await db.waitingUmpires.orderBy('order').last(); const nextOrder = last ? last.order + 1 : 1; @@ -32,6 +32,12 @@ export class WaitingUmpiresService { order: nextOrder }); }); + + if (toPosition !== undefined) { + await this.moveToPosition(umpireId, toPosition); + } + + return id; } /** @@ -39,6 +45,8 @@ export class WaitingUmpiresService { */ async remove(id: number): Promise { await db.waitingUmpires.delete(id); + + await this.reinitOrders(); } async removeByUmpireId(umpireId: number): Promise { @@ -51,7 +59,7 @@ export class WaitingUmpiresService { return; } - await db.waitingUmpires.delete(item.id); + await this.remove(item.id); } /** @@ -67,4 +75,81 @@ export class WaitingUmpiresService { async clear(): Promise { await db.waitingUmpires.clear(); } + + async moveToPosition(umpireId: number, newOrder: number): Promise { + await db.transaction('rw', db.waitingUmpires, async () => { + const current = await db.waitingUmpires + .where('umpireId') + .equals(umpireId) + .first(); + + if (!current) { + return; + } + + const oldOrder = current.order; + + if (oldOrder === newOrder) { + return; + } + + if (newOrder < oldOrder) { + // Moving up: shift affected records down + + const affected = await db.waitingUmpires + .filter( + (item) => + item.order >= newOrder && + item.order < oldOrder && + item.id !== current.id + ) + .toArray(); + + for (const item of affected) { + await db.waitingUmpires.update(item.id!, { + order: item.order + 1 + }); + } + } else { + // Moving down: shift affected records up + + const affected = await db.waitingUmpires + .filter( + (item) => + item.order > oldOrder && + item.order <= newOrder && + item.id !== current.id + ) + .toArray(); + + for (const item of affected) { + await db.waitingUmpires.update(item.id!, { + order: item.order - 1 + }); + } + } + + await db.waitingUmpires.update(current.id!, { + order: newOrder + }); + }); + } + + async reinitOrders(): Promise { + await db.transaction('rw', db.waitingUmpires, async () => { + const items = await db.waitingUmpires.orderBy('order').toArray(); + + for (let i = 0; i < items.length; i++) { + const item = items[i]; + + const expectedOrder = i + 1; + + if (item.order !== expectedOrder) { + await db.waitingUmpires.update(item.id!, { + order: expectedOrder + }); + } + } + }); + } } diff --git a/src/app/tab1/tab1.page.html b/src/app/tab1/tab1.page.html index 1d36256..e19358b 100644 --- a/src/app/tab1/tab1.page.html +++ b/src/app/tab1/tab1.page.html @@ -34,14 +34,17 @@ [lines]="'none'" cdkDropList [id]="`court-umpire-${$index + 1}`" - cdkDropListSortingDisabled - [cdkDropListData]="courtUmpires()" + [cdkDropListData]="umpireByCourt().get($index + 1) ? [umpireByCourt().get($index + 1)] : []" + [cdkDropListEnterPredicate]="canDropUmpire" (cdkDropListDropped)="dropToUmpire($event, $index + 1)"> @if (umpireByCourt().get($index + 1); as umpire) { - - {{ umpire | fullname }} - +
+
+ {{ umpire|fullname }} +
+ {{ umpire|fullname }} +
} @@ -51,14 +54,16 @@ [lines]="'none'" cdkDropList [id]="`court-service-judge-${$index + 1}`" - cdkDropListSortingDisabled - [cdkDropListData]="courtServiceJudges()" + [cdkDropListData]="serviceJudgeByCourt().get($index + 1) ? [serviceJudgeByCourt().get($index + 1)] : []" (cdkDropListDropped)="dropToServiceJudge($event, $index + 1)"> @if (serviceJudgeByCourt().get($index + 1); as umpire) { - - {{ umpire | fullname }} - +
+
+ {{ umpire|fullname }} +
+ {{ umpire|fullname }} +
} @@ -89,14 +94,16 @@ @for (umpire of waitingUmpires(); track umpire.id) { - +
+
+ {{ umpire|fullname }} +
{{ umpire|fullname }} - +
}
@@ -104,14 +111,16 @@ @for (umpire of waitingServiceJudges(); track umpire.id) { - +
+
+ {{ umpire|fullname }} +
{{ umpire|fullname }} - +
}
@@ -124,9 +133,12 @@ (cdkDropListDropped)="dropToRest($event)" [cdkDropListData]="onRest()"> @for (umpire of onRest(); track umpire.id) { - +
+
+ {{ umpire|fullname }} +
{{ umpire|fullname }} - +
} diff --git a/src/app/tab1/tab1.page.scss b/src/app/tab1/tab1.page.scss index 2cd2297..8afc064 100644 --- a/src/app/tab1/tab1.page.scss +++ b/src/app/tab1/tab1.page.scss @@ -1,3 +1,12 @@ .bottom-lists ion-list { min-height: 64px; +} + +.custom-ion-item { + cursor: move; + padding: 10px 15px; + + &.primary { + background-color: var(--ion-color-primary); + } } \ No newline at end of file diff --git a/src/app/tab1/tab1.page.ts b/src/app/tab1/tab1.page.ts index a403442..7d21f91 100644 --- a/src/app/tab1/tab1.page.ts +++ b/src/app/tab1/tab1.page.ts @@ -1,4 +1,4 @@ -import { Component, computed, effect, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { IonHeader, IonToolbar, @@ -9,20 +9,20 @@ import { IonRow, IonList, IonItem, - IonLabel, - IonIcon + IonLabel } from '@ionic/angular/standalone'; import { SettingsService } from '../services/settings-service'; import { UmpireService } from '../services/umpire.service'; -import { Umpire, WaitingAsServiceJudge, WaitingAsUmpire } from 'db'; +import { Umpire } from 'db'; import { WaitingUmpiresService } from '../services/waiting-umpires.service'; import { WaitingServiceJudgesService } from '../services/waiting-service-judges.service'; import { FullnamePipe } from '../fullname-pipe'; import { CdkDrag, CdkDragDrop, + CdkDragPlaceholder, CdkDropList, - DragDropModule + CdkDropListGroup } from '@angular/cdk/drag-drop'; import { CommonModule } from '@angular/common'; import { CourtUmpireService } from '../services/court.umpire.service'; @@ -47,7 +47,8 @@ import { CourtServiceJudgeService } from '../services/court.service.judge.servic CdkDropList, CdkDrag, CommonModule, - DragDropModule + CdkDragPlaceholder, + CdkDropListGroup ] }) export class Tab1Page { @@ -255,7 +256,6 @@ export class Tab1Page { }); dropToRest(event: CdkDragDrop) { - console.log('drop to rest'); if (event.previousContainer === event.container) { return; } else { @@ -266,37 +266,46 @@ export class Tab1Page { } dropToWaitingServiceJudge(event: CdkDragDrop) { + const umpireToMove = event.item.data; if (event.previousContainer === event.container) { - // TODO - } else { - const comingFrom = event.previousContainer.id; - const umpireToMove = event.item.data; - this.waitingServiceJudgeService.add(umpireToMove.id); - - this.removeFromOriginalPlace(umpireToMove, comingFrom); + this.waitingServiceJudgeService.moveToPosition( + umpireToMove.id, + event.currentIndex + 1 + ); + return; } + const comingFrom = event.previousContainer.id; + + this.waitingServiceJudgeService.add( + umpireToMove.id, + event.currentIndex + 1 + ); + + this.removeFromOriginalPlace(umpireToMove, comingFrom); } dropToWaitingUmpire(event: CdkDragDrop) { - console.log( - event.container.data, - event.previousContainer.data, - event.previousContainer.id, - event.container.id - ); + const umpireToMove = event.item.data; if (event.previousContainer === event.container) { - // TODO + this.waitingUmpireService.moveToPosition( + umpireToMove.id, + event.currentIndex + 1 + ); + return; } else { const comingFrom = event.previousContainer.id; - const umpireToMove = event.item.data; - this.waitingUmpireService.add(umpireToMove.id); + this.waitingUmpireService.add(umpireToMove.id, event.currentIndex + 1); this.removeFromOriginalPlace(umpireToMove, comingFrom); } } - dropToUmpire(event: CdkDragDrop, courtNo: number) { - // TODO: stop dropping if there is already another umpire + dropToUmpire(event: CdkDragDrop<(Umpire | undefined)[]>, courtNo: number) { + const targetUmpires = event.container.data; + + if (targetUmpires.length > 0) { + return; + } const comingFrom = event.previousContainer.id; const umpireToMove = event.item.data; @@ -305,8 +314,15 @@ export class Tab1Page { this.removeFromOriginalPlace(umpireToMove, comingFrom); } - dropToServiceJudge(event: CdkDragDrop, courtNo: number) { - // TODO: stop dropping if there is already another umpire + dropToServiceJudge( + event: CdkDragDrop<(Umpire | undefined)[]>, + courtNo: number + ) { + const targetUmpires = event.container.data; + + if (targetUmpires.length > 0) { + return; + } const comingFrom = event.previousContainer.id; const umpireToMove = event.item.data; @@ -335,4 +351,11 @@ export class Tab1Page { this.courtServiceJudgeService.removeByUmpireId(umpireToMove.id); } } + + canDropUmpire = ( + drag: CdkDrag, + drop: CdkDropList + ): boolean => { + return drop.data.length === 0; + }; } diff --git a/src/app/tabs/tabs.page.html b/src/app/tabs/tabs.page.html index 37ef5c2..e6c8c63 100644 --- a/src/app/tabs/tabs.page.html +++ b/src/app/tabs/tabs.page.html @@ -15,7 +15,7 @@ Tab 3 - + Beállítások