Ver código fonte

[update]

再描画処理
poohr 3 semanas atrás
pai
commit
876b7da25e

+ 5
- 1
src/app/pages/event/event.html Ver arquivo

@@ -76,7 +76,11 @@
76 76
             <div>状態</div>
77 77
           </div>
78 78
 
79
-          @if (filteredEventTargets.length > 0) {
79
+          @if (isLoading) {
80
+            <div class="empty-message">
81
+              読み込み中です。
82
+            </div>
83
+          } @else if (filteredEventTargets.length > 0) {
80 84
             @for (target of filteredEventTargets; track target.id) {
81 85
               <div class="event-table-row">
82 86
                 <div>

+ 54
- 10
src/app/pages/event/event.ts Ver arquivo

@@ -1,4 +1,4 @@
1
-import { Component, OnInit } from '@angular/core';
1
+import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
2 2
 import { FormsModule } from '@angular/forms';
3 3
 import { DankaService } from '../../services/dankaService';
4 4
 import { FamilyService } from '../../services/family-service';
@@ -15,6 +15,7 @@ import { AppSideMenu } from '../../share/side-menu/app-side-menu';
15 15
 })
16 16
 export class EventPage implements OnInit{
17 17
   eventTargets: EventTarget[] = [];
18
+  isLoading = true;
18 19
   targetYear: number = new Date().getFullYear();
19 20
   selectedEventType: EventType | 'all' = 'all';
20 21
   selectedStatus: EventStatus | 'all' = 'all';
@@ -38,11 +39,13 @@ export class EventPage implements OnInit{
38 39
     { label: '未案内', value: '未案内' },
39 40
     { label: '案内済', value: '案内済' },
40 41
   ];
42
+  private eventRequestId = 0;
41 43
 
42 44
   constructor(
43 45
     private dankaService: DankaService,
44 46
     private familyService: FamilyService,
45 47
     private eventService: EventService,
48
+    private cdr: ChangeDetectorRef,
46 49
   ) { }
47 50
 
48 51
   ngOnInit(): void {
@@ -54,7 +57,15 @@ export class EventPage implements OnInit{
54 57
   }
55 58
 
56 59
   async createEventTargetList(): Promise<void> {
57
-    this.eventTargets = [];
60
+    const requestId = ++this.eventRequestId;
61
+    const targetYear = this.targetYear;
62
+    const selectedEventType = this.selectedEventType;
63
+    const eventTargets: EventTarget[] = [];
64
+
65
+    if (this.eventTargets.length === 0) {
66
+      this.isLoading = true;
67
+      this.cdr.detectChanges();
68
+    }
58 69
 
59 70
     const families = await this.familyService.getFamilyList();
60 71
 
@@ -62,7 +73,7 @@ export class EventPage implements OnInit{
62 73
       const birthDate = this.parseDate(family.birthDate);
63 74
       if (!birthDate) continue;
64 75
 
65
-      const age = this.targetYear - birthDate.getFullYear();
76
+      const age = targetYear - birthDate.getFullYear();
66 77
       const eventTypes = this.getEventTypes(age);
67 78
       if (eventTypes.length === 0) continue;
68 79
 
@@ -71,8 +82,8 @@ export class EventPage implements OnInit{
71 82
 
72 83
       for (const eventType of eventTypes) {
73 84
         if (
74
-          this.selectedEventType !== 'all' &&
75
-          this.selectedEventType !== eventType
85
+          selectedEventType !== 'all' &&
86
+          selectedEventType !== eventType
76 87
         ) {
77 88
           continue;
78 89
         }
@@ -82,14 +93,14 @@ export class EventPage implements OnInit{
82 93
         const defaultStatus: EventStatus =
83 94
           Number(family.id) % 2 === 0 ? '案内済' : '未案内';
84 95
 
85
-        this.eventTargets.push({
96
+        eventTargets.push({
86 97
           id,
87 98
           dankaId: family.dankaId,
88 99
           name: family.name,
89 100
           furigana: family.furigana,
90 101
           householdName: danka?.householdName ?? '不明',
91 102
           relationship: family.relationship || '未登録',
92
-          birthDate: family.birthDate,
103
+          birthDate: this.formatDateForValue(birthDate),
93 104
           age,
94 105
           eventType,
95 106
           note: family.note,
@@ -98,13 +109,19 @@ export class EventPage implements OnInit{
98 109
       }
99 110
     }
100 111
 
101
-    this.eventTargets.sort(
112
+    if (requestId !== this.eventRequestId) {
113
+      return;
114
+    }
115
+
116
+    this.eventTargets = eventTargets.sort(
102 117
       (a, b) =>
103 118
         this.getEventSortOrder(a.eventType) -
104 119
         this.getEventSortOrder(b.eventType) ||
105 120
         a.age - b.age ||
106 121
         a.name.localeCompare(b.name, 'ja'),
107 122
     );
123
+    this.isLoading = false;
124
+    this.cdr.detectChanges();
108 125
   }
109 126
 
110 127
   changeEventType(eventType: EventType | 'all'): void {
@@ -128,7 +145,7 @@ export class EventPage implements OnInit{
128 145
           target.eventType,
129 146
           target.note,
130 147
           target.status,
131
-        ].some((value) => value.includes(keyword));
148
+        ].some((value) => this.includesKeyword(value, keyword));
132 149
 
133 150
       return matchesStatus && matchesKeyword;
134 151
     });
@@ -162,11 +179,38 @@ export class EventPage implements OnInit{
162 179
     return ['稚児行列', '七五三', '成人式', '米寿'].indexOf(eventType);
163 180
   }
164 181
 
165
-  private parseDate(value: string): Date | null {
182
+  private parseDate(value: unknown): Date | null {
183
+    if (!value) {
184
+      return null;
185
+    }
186
+
187
+    if (value instanceof Date) {
188
+      return value;
189
+    }
190
+
191
+    if (typeof value === 'object' && 'toDate' in value && typeof value.toDate === 'function') {
192
+      return value.toDate();
193
+    }
194
+
195
+    if (typeof value !== 'string') {
196
+      return null;
197
+    }
198
+
166 199
     const [year, month, day] = value.split('-').map(Number);
167 200
     if (!year || !month || !day) {
168 201
       return null;
169 202
     }
170 203
     return new Date(year, month - 1, day);
171 204
   }
205
+
206
+  private includesKeyword(value: unknown, keyword: string): boolean {
207
+    return String(value ?? '').includes(keyword);
208
+  }
209
+
210
+  private formatDateForValue(date: Date): string {
211
+    const year = date.getFullYear();
212
+    const month = String(date.getMonth() + 1).padStart(2, '0');
213
+    const day = String(date.getDate()).padStart(2, '0');
214
+    return `${year}-${month}-${day}`;
215
+  }
172 216
 }

+ 5
- 1
src/app/pages/memorial-list/memorial-list.html Ver arquivo

@@ -69,7 +69,11 @@
69 69
             <div>詳細</div>
70 70
           </div>
71 71
 
72
-          @if (filteredMemorialList.length > 0) {
72
+          @if (isLoading) {
73
+            <div class="empty-message">
74
+              読み込み中です。
75
+            </div>
76
+          } @else if (filteredMemorialList.length > 0) {
73 77
             @for (memorial of filteredMemorialList; track memorial.id) {
74 78
               <div class="memorial-table-row">
75 79
                 <div class="person-name">

+ 69
- 13
src/app/pages/memorial-list/memorial-list.ts Ver arquivo

@@ -1,4 +1,4 @@
1
-import { Component, OnInit } from '@angular/core';
1
+import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
2 2
 import { ActivatedRoute, Router, RouterLink } from '@angular/router';
3 3
 import { Memorial } from '../../models/memorial';
4 4
 import { DankaService } from '../../services/dankaService';
@@ -15,9 +15,11 @@ import { FormsModule } from '@angular/forms';
15 15
 })
16 16
 export class MemorialList implements OnInit{
17 17
   memorialList: Memorial[] = [];
18
+  isLoading = true;
18 19
   targetYear: number = new Date().getFullYear();
19 20
   selectedMemorialType = 'all';
20 21
   searchKeyword = '';
22
+  private memorialRequestId = 0;
21 23
   yearOptions: number[] = [
22 24
     this.targetYear - 1,
23 25
     this.targetYear,
@@ -45,6 +47,7 @@ export class MemorialList implements OnInit{
45 47
   constructor(
46 48
     private dankaService: DankaService,
47 49
     private kakochoService: KakochoService,
50
+    private cdr: ChangeDetectorRef,
48 51
   ) {
49 52
 
50 53
   }
@@ -57,20 +60,31 @@ export class MemorialList implements OnInit{
57 60
   }
58 61
 
59 62
   async createMemorialList(): Promise<void> {
60
-    this.memorialList = [];
63
+    const requestId = ++this.memorialRequestId;
64
+    const targetYear = this.targetYear;
65
+    const selectedMemorialType = this.selectedMemorialType;
66
+    const memorialList: Memorial[] = [];
67
+
68
+    if (this.memorialList.length === 0) {
69
+      this.isLoading = true;
70
+      this.cdr.detectChanges();
71
+    }
61 72
 
62 73
     const kakochoList = await this.kakochoService.getKakochoList();
63 74
 
64 75
     for (const kakocho of kakochoList) {
65
-      const deathYear = Number(kakocho.deathDate.slice(0, 4));
66
-      const yearDiff = this.targetYear - deathYear;
76
+      const deathDate = this.parseDate(kakocho.deathDate);
77
+      if (!deathDate) continue;
78
+
79
+      const deathYear = deathDate.getFullYear();
80
+      const yearDiff = targetYear - deathYear;
67 81
 
68 82
       const memorialType = this.getMemorialType(yearDiff);
69 83
       if (memorialType === '') continue;
70 84
 
71 85
       if (
72
-        this.selectedMemorialType !== 'all' &&
73
-        this.selectedMemorialType !== memorialType
86
+        selectedMemorialType !== 'all' &&
87
+        selectedMemorialType !== memorialType
74 88
       ) {
75 89
         continue;
76 90
       }
@@ -85,15 +99,19 @@ export class MemorialList implements OnInit{
85 99
         kaimyo: kakocho.kaimyo,
86 100
         relationship: kakocho.relationship,
87 101
         householdName: danka?.householdName ?? '不明',
88
-        deathDate: kakocho.deathDate,
102
+        deathDate: this.formatDateForValue(deathDate),
89 103
         memorialType,
90 104
         note: kakocho.note,
91 105
       };
92 106
 
93
-      this.memorialList.push(memorialTarget);
107
+      memorialList.push(memorialTarget);
94 108
     }
95 109
 
96
-    this.memorialList.sort((a, b) => {
110
+    if (requestId !== this.memorialRequestId) {
111
+      return;
112
+    }
113
+
114
+    this.memorialList = memorialList.sort((a, b) => {
97 115
       const deathDateA = new Date(a.deathDate).getTime();
98 116
       const deathDateB = new Date(b.deathDate).getTime();
99 117
 
@@ -103,6 +121,8 @@ export class MemorialList implements OnInit{
103 121
 
104 122
       return a.name.localeCompare(b.name, 'ja');
105 123
     });
124
+    this.isLoading = false;
125
+    this.cdr.detectChanges();
106 126
   }
107 127
 
108 128
   changeMemorialType(memorialType: string): void {
@@ -126,17 +146,21 @@ export class MemorialList implements OnInit{
126 146
         memorial.householdName,
127 147
         memorial.memorialType,
128 148
         memorial.note,
129
-      ].some((value) => value.includes(keyword)),
149
+      ].some((value) => this.includesKeyword(value, keyword)),
130 150
     );
131 151
   }
132 152
 
153
+  private includesKeyword(value: unknown, keyword: string): boolean {
154
+    return String(value ?? '').includes(keyword);
155
+  }
156
+
133 157
   formatDeathDate(deathDate: string): string {
134
-    const [, month, day] = deathDate.split('-').map(Number);
135
-    if (!month || !day) {
158
+    const date = this.parseDate(deathDate);
159
+    if (!date) {
136 160
       return '未登録';
137 161
     }
138 162
 
139
-    return `${month}月${day}日`;
163
+    return `${date.getMonth() + 1}月${date.getDate()}日`;
140 164
   }
141 165
 
142 166
   getMemorialType(yearDiff: number) {
@@ -173,4 +197,36 @@ export class MemorialList implements OnInit{
173 197
         return '';
174 198
     }
175 199
   }
200
+
201
+  private parseDate(value: unknown): Date | null {
202
+    if (!value) {
203
+      return null;
204
+    }
205
+
206
+    if (value instanceof Date) {
207
+      return value;
208
+    }
209
+
210
+    if (typeof value === 'object' && 'toDate' in value && typeof value.toDate === 'function') {
211
+      return value.toDate();
212
+    }
213
+
214
+    if (typeof value !== 'string') {
215
+      return null;
216
+    }
217
+
218
+    const [year, month, day] = value.split('-').map(Number);
219
+    if (!year || !month || !day) {
220
+      return null;
221
+    }
222
+
223
+    return new Date(year, month - 1, day);
224
+  }
225
+
226
+  private formatDateForValue(date: Date): string {
227
+    const year = date.getFullYear();
228
+    const month = String(date.getMonth() + 1).padStart(2, '0');
229
+    const day = String(date.getDate()).padStart(2, '0');
230
+    return `${year}-${month}-${day}`;
231
+  }
176 232
 }

+ 4
- 1
src/app/pages/search/search.ts Ver arquivo

@@ -1,4 +1,4 @@
1
-import { Component, OnInit } from '@angular/core';
1
+import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
2 2
 import { FormsModule } from '@angular/forms';
3 3
 import { ActivatedRoute, RouterLink } from '@angular/router';
4 4
 import { Danka } from '../../models/danka';
@@ -37,6 +37,7 @@ export class Search implements OnInit{
37 37
     private familyService: FamilyService,
38 38
     private kakochoService: KakochoService,
39 39
     private route: ActivatedRoute,
40
+    private cdr: ChangeDetectorRef,
40 41
   ) { }
41 42
 
42 43
   ngOnInit(): void {
@@ -153,6 +154,7 @@ export class Search implements OnInit{
153 154
     this.familyResults = [];
154 155
     this.kakochoResults = [];
155 156
     this.totalResultCount = 0;
157
+    this.cdr.detectChanges();
156 158
   }
157 159
 
158 160
   private includesKeyword(value: unknown, keyword: string): boolean {
@@ -180,5 +182,6 @@ export class Search implements OnInit{
180 182
       dankaResults.length +
181 183
       familyResults.length +
182 184
       kakochoResults.length;
185
+    this.cdr.detectChanges();
183 186
   }
184 187
 }

Carregando…
Cancelar
Salvar