kuni 3 tygodni temu
rodzic
commit
5b696f87f5

+ 50
- 47
src/app/pages/danka-list/danka-list.ts Wyświetl plik

1
-import { Component } from '@angular/core';
1
+import { Component, OnInit } from '@angular/core';
2
 import { RouterLink } from '@angular/router';
2
 import { RouterLink } from '@angular/router';
3
 import { DankaService } from '../../services/dankaService';
3
 import { DankaService } from '../../services/dankaService';
4
 import { FamilyService } from '../../services/family-service';
4
 import { FamilyService } from '../../services/family-service';
26
   templateUrl: './danka-list.html',
26
   templateUrl: './danka-list.html',
27
   styleUrl: './danka-list.scss',
27
   styleUrl: './danka-list.scss',
28
 })
28
 })
29
-export class DankaList {
29
+export class DankaList implements OnInit {
30
   dankaList: Danka[] = [];
30
   dankaList: Danka[] = [];
31
   filterDankaList: Danka[] = [];
31
   filterDankaList: Danka[] = [];
32
   searchKeyword: string = '';
32
   searchKeyword: string = '';
33
   dankaDisplay: number = 0;
33
   dankaDisplay: number = 0;
34
   selectedFilter = 'all';
34
   selectedFilter = 'all';
35
   selectedKanaRow: KanaRowValue = 'all';
35
   selectedKanaRow: KanaRowValue = 'all';
36
+
36
   kanaRows: { label: string; value: KanaRowValue }[] = [
37
   kanaRows: { label: string; value: KanaRowValue }[] = [
37
     { label: '全件', value: 'all' },
38
     { label: '全件', value: 'all' },
38
     { label: 'あ行', value: 'a' },
39
     { label: 'あ行', value: 'a' },
48
   ];
49
   ];
49
 
50
 
50
   private readonly kanaRowMap: Record<Exclude<KanaRowValue, 'all'>, string[]> = {
51
   private readonly kanaRowMap: Record<Exclude<KanaRowValue, 'all'>, string[]> = {
51
-    a: ['あ', 'い', 'う', 'え', 'お', 'ア', 'イ', 'ウ', 'エ', 'オ'],
52
-    ka: ['か', 'き', 'く', 'け', 'こ', 'が', 'ぎ', 'ぐ', 'げ', 'ご', 'カ', 'キ', 'ク', 'ケ', 'コ', 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ'],
53
-    sa: ['さ', 'し', 'す', 'せ', 'そ', 'ざ', 'じ', 'ず', 'ぜ', 'ぞ', 'サ', 'シ', 'ス', 'セ', 'ソ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ'],
54
-    ta: ['た', 'ち', 'つ', 'て', 'と', 'だ', 'ぢ', 'づ', 'で', 'ど', 'タ', 'チ', 'ツ', 'テ', 'ト', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド'],
55
-    na: ['な', 'に', 'ぬ', 'ね', 'の', 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ'],
56
-    ha: ['は', 'ひ', 'ふ', 'へ', 'ほ', 'ば', 'び', 'ぶ', 'べ', 'ぼ', 'ぱ', 'ぴ', 'ぷ', 'ぺ', 'ぽ', 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ', 'バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ'],
57
-    ma: ['ま', 'み', 'む', 'め', 'も', 'マ', 'ミ', 'ム', 'メ', 'モ'],
58
-    ya: ['や', 'ゆ', 'よ', 'ヤ', 'ユ', 'ヨ'],
59
-    ra: ['ら', 'り', 'る', 'れ', 'ろ', 'ラ', 'リ', 'ル', 'レ', 'ロ'],
60
-    wa: ['わ', 'を', 'ん', 'ワ', 'ヲ', 'ン'],
52
+    a: ['あ','い','う','え','お','ア','イ','ウ','エ','オ'],
53
+    ka: ['か','き','く','け','こ','が','ぎ','ぐ','げ','ご','カ','キ','ク','ケ','コ','ガ','ギ','グ','ゲ','ゴ'],
54
+    sa: ['さ','し','す','せ','そ','ざ','じ','ず','ぜ','ぞ','サ','シ','ス','セ','ソ','ザ','ジ','ズ','ゼ','ゾ'],
55
+    ta: ['た','ち','つ','て','と','だ','ぢ','づ','で','ど','タ','チ','ツ','テ','ト','ダ','ヂ','ヅ','デ','ド'],
56
+    na: ['な','に','ぬ','ね','の','ナ','ニ','ヌ','ネ','ノ'],
57
+    ha: ['は','ひ','ふ','へ','ほ','ば','び','ぶ','べ','ぼ','ぱ','ぴ','ぷ','ぺ','ぽ','ハ','ヒ','フ','ヘ','ホ','バ','ビ','ブ','ベ','ボ','パ','ピ','プ','ペ','ポ'],
58
+    ma: ['ま','み','む','め','も','マ','ミ','ム','メ','モ'],
59
+    ya: ['や','ゆ','よ','ヤ','ユ','ヨ'],
60
+    ra: ['ら','り','る','れ','ろ','ラ','リ','ル','レ','ロ'],
61
+    wa: ['わ','を','ん','ワ','ヲ','ン'],
61
   };
62
   };
62
 
63
 
63
   constructor(
64
   constructor(
64
     private dankaService: DankaService,
65
     private dankaService: DankaService,
65
     private familyService: FamilyService,
66
     private familyService: FamilyService,
66
-  ) {
67
-    this.dankaList = this.dankaService.getDankaList();
67
+  ) {}
68
+
69
+  // 非同期初期化
70
+  ngOnInit(): void {
71
+    this.init();
72
+  }
73
+
74
+  async init(): Promise<void> {
75
+    this.dankaList = await this.dankaService.getDankaList();
68
     this.showAllDanka();
76
     this.showAllDanka();
69
   }
77
   }
70
 
78
 
71
-  //全件タグで絞り込み
72
   showAllDanka() {
79
   showAllDanka() {
73
     this.selectedFilter = 'all';
80
     this.selectedFilter = 'all';
74
     this.selectedKanaRow = 'all';
81
     this.selectedKanaRow = 'all';
77
     this.dankaDisplay = this.filterDankaList.length;
84
     this.dankaDisplay = this.filterDankaList.length;
78
   }
85
   }
79
 
86
 
80
-  //電話番号タグで絞り込み
81
   filterPhoneAvailable() {
87
   filterPhoneAvailable() {
82
     this.selectedFilter = 'phone';
88
     this.selectedFilter = 'phone';
83
     this.selectedKanaRow = 'all';
89
     this.selectedKanaRow = 'all';
84
-    //電話番号タブに該当する檀家を表示
85
-    this.filterDankaList = this.dankaList.filter((danka) => {
86
-      return danka.phones.some((phone) => phone.tel.trim() !== '');
87
-    });
90
+
91
+    this.filterDankaList = this.dankaList.filter((danka) =>
92
+      danka.phones.some((phone) => phone.tel.trim() !== '')
93
+    );
94
+
88
     this.dankaDisplay = this.filterDankaList.length;
95
     this.dankaDisplay = this.filterDankaList.length;
89
   }
96
   }
90
 
97
 
91
-  //検索処理
92
   searchDanka() {
98
   searchDanka() {
93
     this.selectedFilter = 'search';
99
     this.selectedFilter = 'search';
94
     this.selectedKanaRow = 'all';
100
     this.selectedKanaRow = 'all';
95
-    //検索欄に入力された値から余白を削除
101
+
96
     const keyword = this.searchKeyword.trim();
102
     const keyword = this.searchKeyword.trim();
97
-    //検索欄が空の場合は檀家の一覧を表示
103
+
98
     if (keyword === '') {
104
     if (keyword === '') {
99
-      this.filterDankaList = this.dankaList;
100
-      this.dankaDisplay = this.filterDankaList.length;
105
+      this.showAllDanka();
101
       return;
106
       return;
102
     }
107
     }
103
 
108
 
104
-    //検索欄に値がある場合は値に該当する内容を表示
105
-    this.filterDankaList = this.dankaList.filter((danka) => {
106
-      return (
107
-        danka.householdName.includes(keyword) ||
108
-        danka.householdFurigana.includes(keyword) ||
109
-        danka.householder.includes(keyword) ||
110
-        danka.householderFurigana.includes(keyword) ||
111
-        danka.postalCode.includes(keyword) ||
112
-        danka.address.includes(keyword) ||
113
-        danka.phones.some((phone) => phone.tel.includes(keyword) || phone.note.includes(keyword))
114
-      );
115
-    });
109
+    this.filterDankaList = this.dankaList.filter((danka) =>
110
+      danka.householdName.includes(keyword) ||
111
+      danka.householdFurigana.includes(keyword) ||
112
+      danka.householder.includes(keyword) ||
113
+      danka.householderFurigana.includes(keyword) ||
114
+      danka.postalCode.includes(keyword) ||
115
+      danka.address.includes(keyword) ||
116
+      danka.phones.some((p) => p.tel.includes(keyword) || p.note.includes(keyword))
117
+    );
118
+
116
     this.dankaDisplay = this.filterDankaList.length;
119
     this.dankaDisplay = this.filterDankaList.length;
117
-    console.log(this.dankaDisplay);
118
   }
120
   }
119
 
121
 
120
   filterByKanaRow(row: KanaRowValue): void {
122
   filterByKanaRow(row: KanaRowValue): void {
123
     this.searchKeyword = '';
125
     this.searchKeyword = '';
124
 
126
 
125
     if (row === 'all') {
127
     if (row === 'all') {
126
-      this.filterDankaList = this.dankaList;
127
-      this.dankaDisplay = this.filterDankaList.length;
128
+      this.showAllDanka();
128
       return;
129
       return;
129
     }
130
     }
130
 
131
 
131
-    this.filterDankaList = this.dankaList.filter((danka) => {
132
-      const firstKana = this.getDankaSortText(danka).charAt(0);
132
+    this.filterDankaList = this.dankaList.filter(async (danka) => {
133
+      const firstKana = (await this.getDankaSortText(danka)).charAt(0);
133
       return this.kanaRowMap[row].includes(firstKana);
134
       return this.kanaRowMap[row].includes(firstKana);
134
     });
135
     });
136
+
135
     this.dankaDisplay = this.filterDankaList.length;
137
     this.dankaDisplay = this.filterDankaList.length;
136
   }
138
   }
137
 
139
 
143
     this.dankaDisplay = 0;
145
     this.dankaDisplay = 0;
144
   }
146
   }
145
 
147
 
146
-  private getDankaSortText(danka: Danka): string {
148
+  private async getDankaSortText(danka: Danka): Promise<string> {
147
     const householderName = this.normalizeName(danka.householder);
149
     const householderName = this.normalizeName(danka.householder);
148
-    const householderFamily = this.familyService
149
-      .getFamiliesByDankaId(danka.id)
150
-      .find((family) => this.normalizeName(family.name) === householderName);
150
+
151
+    const householderFamily = (await this.familyService
152
+      .getFamiliesByDankaId(danka.id))
153
+      .find((f) => this.normalizeName(f.name) === householderName);
151
 
154
 
152
     return (householderFamily?.furigana || danka.householder).trim();
155
     return (householderFamily?.furigana || danka.householder).trim();
153
   }
156
   }
155
   private normalizeName(name: string): string {
158
   private normalizeName(name: string): string {
156
     return name.replace(/\s/g, '');
159
     return name.replace(/\s/g, '');
157
   }
160
   }
158
-}
161
+}

+ 20
- 16
src/app/pages/dashboard/dashboard.ts Wyświetl plik

49
     this.setUpcomingMemorials();
49
     this.setUpcomingMemorials();
50
   }
50
   }
51
 
51
 
52
-  private setRecentDankaList(): void {
53
-    this.recentDankaList = this.dankaService.getRecentDankaList(5).map((danka) => ({
54
-      danka,
55
-      nextMemorialLabel: this.getNextMemorialLabel(danka.id),
56
-      updatedAtLabel: this.formatUpdatedAt(danka.updatedAt),
57
-    }));
52
+  private async setRecentDankaList(): Promise<void> {
53
+    const dankaList = await this.dankaService.getRecentDankaList(5);
54
+
55
+    this.recentDankaList = await Promise.all(
56
+      dankaList.map(async (danka) => ({
57
+        danka,
58
+        nextMemorialLabel: await this.getNextMemorialLabel(danka.id),
59
+        updatedAtLabel: this.formatUpdatedAt(danka.updatedAt),
60
+      }))
61
+    );
58
   }
62
   }
59
 
63
 
60
-  private setWeeklyMemorialSummary(): void {
64
+  private async setWeeklyMemorialSummary(): Promise<void> {
61
     const today = this.toDateOnly(new Date());
65
     const today = this.toDateOnly(new Date());
62
     const weekEnd = this.addDays(this.getWeekStart(today), 6);
66
     const weekEnd = this.addDays(this.getWeekStart(today), 6);
63
 
67
 
64
-    const weeklyMemorials = this.kakochoService.getKakochoList().filter((kakocho) => {
68
+    const weeklyMemorials = (await this.kakochoService.getKakochoList()).filter((kakocho) => {
65
       const deathDate = this.parseDate(kakocho.deathDate);
69
       const deathDate = this.parseDate(kakocho.deathDate);
66
       if (!deathDate) {
70
       if (!deathDate) {
67
         return false;
71
         return false;
83
     this.upcomingWeeklyMemorialCount = this.weeklyMemorialCount - this.todayMemorialCount;
87
     this.upcomingWeeklyMemorialCount = this.weeklyMemorialCount - this.todayMemorialCount;
84
   }
88
   }
85
 
89
 
86
-  private setMonthlyMemorialSummary(): void {
90
+  private async setMonthlyMemorialSummary(): Promise<void> {
87
     const today = this.toDateOnly(new Date());
91
     const today = this.toDateOnly(new Date());
88
 
92
 
89
-    this.monthlyMemorialCount = this.kakochoService.getKakochoList().filter((kakocho) => {
93
+    this.monthlyMemorialCount = (await this.kakochoService.getKakochoList()).filter((kakocho) => {
90
       const deathDate = this.parseDate(kakocho.deathDate);
94
       const deathDate = this.parseDate(kakocho.deathDate);
91
       if (!deathDate || !this.isMemorialTarget(deathDate)) {
95
       if (!deathDate || !this.isMemorialTarget(deathDate)) {
92
         return false;
96
         return false;
96
     }).length;
100
     }).length;
97
   }
101
   }
98
 
102
 
99
-  private setUpcomingMemorials(): void {
103
+  private async setUpcomingMemorials(): Promise<void> {
100
     const today = this.toDateOnly(new Date());
104
     const today = this.toDateOnly(new Date());
101
     const endDate = this.addDays(today, 30);
105
     const endDate = this.addDays(today, 30);
102
 
106
 
103
-    this.upcomingMemorials = this.kakochoService
104
-      .getKakochoList()
107
+    this.upcomingMemorials = (await this.kakochoService
108
+      .getKakochoList())
105
       .map((kakocho): UpcomingMemorial | null => {
109
       .map((kakocho): UpcomingMemorial | null => {
106
         const deathDate = this.parseDate(kakocho.deathDate);
110
         const deathDate = this.parseDate(kakocho.deathDate);
107
         if (!deathDate) {
111
         if (!deathDate) {
167
     return `${date.getMonth() + 1}月${date.getDate()}日`;
171
     return `${date.getMonth() + 1}月${date.getDate()}日`;
168
   }
172
   }
169
 
173
 
170
-  private getNextMemorialLabel(dankaId: string): string {
174
+  private async getNextMemorialLabel(dankaId: string): Promise<string> {
171
     const today = this.toDateOnly(new Date());
175
     const today = this.toDateOnly(new Date());
172
-    const nextMemorial = this.kakochoService
173
-      .getKakochoByDankaId(dankaId)
176
+    const nextMemorial = (await this.kakochoService
177
+      .getKakochoByDankaId(dankaId))
174
       .map((kakocho) => {
178
       .map((kakocho) => {
175
         const deathDate = this.parseDate(kakocho.deathDate);
179
         const deathDate = this.parseDate(kakocho.deathDate);
176
         if (!deathDate) {
180
         if (!deathDate) {

+ 48
- 12
src/app/services/dankaService.ts Wyświetl plik

60
     await deleteDoc(ref);
60
     await deleteDoc(ref);
61
   }
61
   }
62
 
62
 
63
+  // -----------------------------
64
+  // 最近開いた檀家
65
+  // -----------------------------
66
+
63
   private getRecentDankaIds(): string[] {
67
   private getRecentDankaIds(): string[] {
64
-    if (!this.canUseLocalStorage()) {
65
-      return [];
66
-    }
68
+    if (!this.canUseLocalStorage()) return [];
67
 
69
 
68
     const value = localStorage.getItem(this.recentDankaStorageKey);
70
     const value = localStorage.getItem(this.recentDankaStorageKey);
69
-    if (!value) {
70
-      return [];
71
-    }
71
+    if (!value) return [];
72
 
72
 
73
     try {
73
     try {
74
       const parsed = JSON.parse(value);
74
       const parsed = JSON.parse(value);
75
-      return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];
75
+      return Array.isArray(parsed)
76
+        ? parsed.filter((id): id is string => typeof id === 'string')
77
+        : [];
76
     } catch {
78
     } catch {
77
       return [];
79
       return [];
78
     }
80
     }
79
   }
81
   }
80
 
82
 
81
   private saveRecentDankaIds(ids: string[]): void {
83
   private saveRecentDankaIds(ids: string[]): void {
82
-    if (!this.canUseLocalStorage()) {
83
-      return;
84
-    }
85
-
84
+    if (!this.canUseLocalStorage()) return;
86
     localStorage.setItem(this.recentDankaStorageKey, JSON.stringify(ids));
85
     localStorage.setItem(this.recentDankaStorageKey, JSON.stringify(ids));
87
   }
86
   }
88
 
87
 
89
   private canUseLocalStorage(): boolean {
88
   private canUseLocalStorage(): boolean {
90
     return typeof localStorage !== 'undefined';
89
     return typeof localStorage !== 'undefined';
91
   }
90
   }
92
-}
91
+
92
+  // ★ここが重要:async化
93
+  async recordDankaOpened(id: string): Promise<void> {
94
+    const danka = await this.getDankaById(id);
95
+    if (!danka) return;
96
+
97
+    const recentIds = [
98
+      id,
99
+      ...this.getRecentDankaIds().filter(rid => rid !== id),
100
+    ].slice(0, 5);
101
+
102
+    this.saveRecentDankaIds(recentIds);
103
+  }
104
+
105
+  // ★ここも async 必須
106
+  async getRecentDankaList(limit = 5): Promise<Danka[]> {
107
+    const ids = this.getRecentDankaIds().slice(0, limit);
108
+
109
+    const list = await Promise.all(
110
+      ids.map(id => this.getDankaById(id))
111
+    );
112
+
113
+    const filtered = list.filter((d): d is Danka => d !== undefined);
114
+
115
+    if (filtered.length > 0) {
116
+      return filtered;
117
+    }
118
+
119
+    // fallback(updatedAtがある前提なら)
120
+    const all = await this.getDankaList();
121
+
122
+    return [...all]
123
+      .sort((a: any, b: any) =>
124
+        (b.updatedAt ?? '').localeCompare(a.updatedAt ?? '')
125
+      )
126
+      .slice(0, limit);
127
+  }
128
+}

Ładowanie…
Anuluj
Zapisz