|
|
@@ -11,6 +11,13 @@ import { AppHeader } from '../../share/header/app-header';
|
|
11
|
11
|
import { AppSideMenu } from '../../share/side-menu/app-side-menu';
|
|
12
|
12
|
import { MarriageRelationService } from '../../services/marriage-relation-service';
|
|
13
|
13
|
|
|
|
14
|
+interface NextMemorial {
|
|
|
15
|
+ name: string;
|
|
|
16
|
+ memorialType: string;
|
|
|
17
|
+ targetYear: number;
|
|
|
18
|
+ deathDate: string;
|
|
|
19
|
+}
|
|
|
20
|
+
|
|
14
|
21
|
@Component({
|
|
15
|
22
|
selector: 'app-danka-detail',
|
|
16
|
23
|
imports: [AppHeader, AppSideMenu, RouterLink],
|
|
|
@@ -22,6 +29,7 @@ export class DankaDetail {
|
|
22
|
29
|
families: Family[] = [];
|
|
23
|
30
|
kakocholist: Kakocho[] = [];
|
|
24
|
31
|
marriageRelations: MarriageRelation[] = [];
|
|
|
32
|
+ nextMemorial: NextMemorial | undefined;
|
|
25
|
33
|
currentYear = new Date().getFullYear();
|
|
26
|
34
|
|
|
27
|
35
|
selectedTab: 'basic' | 'family' | 'kakocho' | 'familyTree' = 'basic';
|
|
|
@@ -47,9 +55,10 @@ export class DankaDetail {
|
|
47
|
55
|
if (id) {
|
|
48
|
56
|
this.danka = this.dankaService.getDankaById(id);
|
|
49
|
57
|
this.marriageRelations = this.marriageRelationService.getMarriageRelationsByDankaId(id);
|
|
50
|
|
- this.families = this.familyService.getFamiliesByDankaId(id);
|
|
|
58
|
+ this.families = this.sortFamiliesByHouseholder(this.familyService.getFamiliesByDankaId(id));
|
|
51
|
59
|
this.selectedFamily = this.families[0];
|
|
52
|
60
|
this.kakocholist = this.kakochoService.getKakochoByDankaId(id);
|
|
|
61
|
+ this.nextMemorial = this.getNextMemorial();
|
|
53
|
62
|
}
|
|
54
|
63
|
}
|
|
55
|
64
|
|
|
|
@@ -75,10 +84,118 @@ export class DankaDetail {
|
|
75
|
84
|
return this.currentYear - new Date(deathDate).getFullYear() + 1;
|
|
76
|
85
|
}
|
|
77
|
86
|
|
|
|
87
|
+ formatUpdatedAt(updatedAt: string): string {
|
|
|
88
|
+ const date = this.parseDate(updatedAt);
|
|
|
89
|
+ if (!date) {
|
|
|
90
|
+ return '未登録';
|
|
|
91
|
+ }
|
|
|
92
|
+
|
|
|
93
|
+ return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
|
|
|
94
|
+ }
|
|
|
95
|
+
|
|
|
96
|
+ getMemorialType(deathDate: string): string {
|
|
|
97
|
+ const deathYear = Number(deathDate.slice(0, 4));
|
|
|
98
|
+ const yearDiff = this.currentYear - deathYear;
|
|
|
99
|
+
|
|
|
100
|
+ switch (yearDiff) {
|
|
|
101
|
+ case 1:
|
|
|
102
|
+ return '一周忌';
|
|
|
103
|
+ case 2:
|
|
|
104
|
+ return '三回忌';
|
|
|
105
|
+ case 6:
|
|
|
106
|
+ return '七回忌';
|
|
|
107
|
+ case 12:
|
|
|
108
|
+ return '十三回忌';
|
|
|
109
|
+ case 16:
|
|
|
110
|
+ return '十七回忌';
|
|
|
111
|
+ case 22:
|
|
|
112
|
+ return '二十三回忌';
|
|
|
113
|
+ default:
|
|
|
114
|
+ return '';
|
|
|
115
|
+ }
|
|
|
116
|
+ }
|
|
|
117
|
+
|
|
|
118
|
+ private getNextMemorial(): NextMemorial | undefined {
|
|
|
119
|
+ const today = this.toDateOnly(new Date());
|
|
|
120
|
+
|
|
|
121
|
+ return this.kakocholist
|
|
|
122
|
+ .map((kakocho) => {
|
|
|
123
|
+ const memorialType = this.getMemorialType(kakocho.deathDate);
|
|
|
124
|
+ const deathDate = this.parseDate(kakocho.deathDate);
|
|
|
125
|
+
|
|
|
126
|
+ if (!memorialType || !deathDate) {
|
|
|
127
|
+ return undefined;
|
|
|
128
|
+ }
|
|
|
129
|
+
|
|
|
130
|
+ const memorialDate = new Date(
|
|
|
131
|
+ this.currentYear,
|
|
|
132
|
+ deathDate.getMonth(),
|
|
|
133
|
+ deathDate.getDate(),
|
|
|
134
|
+ );
|
|
|
135
|
+
|
|
|
136
|
+ if (memorialDate < today) {
|
|
|
137
|
+ return undefined;
|
|
|
138
|
+ }
|
|
|
139
|
+
|
|
|
140
|
+ return {
|
|
|
141
|
+ memorialDate,
|
|
|
142
|
+ memorial: {
|
|
|
143
|
+ name: kakocho.name,
|
|
|
144
|
+ memorialType,
|
|
|
145
|
+ targetYear: this.currentYear,
|
|
|
146
|
+ deathDate: kakocho.deathDate,
|
|
|
147
|
+ },
|
|
|
148
|
+ };
|
|
|
149
|
+ })
|
|
|
150
|
+ .filter(
|
|
|
151
|
+ (item): item is { memorialDate: Date; memorial: NextMemorial } => item !== undefined,
|
|
|
152
|
+ )
|
|
|
153
|
+ .sort(
|
|
|
154
|
+ (a, b) =>
|
|
|
155
|
+ a.memorialDate.getTime() - b.memorialDate.getTime() ||
|
|
|
156
|
+ a.memorial.name.localeCompare(b.memorial.name, 'ja'),
|
|
|
157
|
+ )[0]?.memorial;
|
|
|
158
|
+ }
|
|
|
159
|
+
|
|
|
160
|
+ private toDateOnly(date: Date): Date {
|
|
|
161
|
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
|
162
|
+ }
|
|
|
163
|
+
|
|
|
164
|
+ private parseDate(value: string): Date | null {
|
|
|
165
|
+ const [year, month, day] = value.split('-').map(Number);
|
|
|
166
|
+ if (!year || !month || !day) {
|
|
|
167
|
+ return null;
|
|
|
168
|
+ }
|
|
|
169
|
+ return new Date(year, month - 1, day);
|
|
|
170
|
+ }
|
|
|
171
|
+
|
|
78
|
172
|
selectFamily(family: Family): void {
|
|
79
|
173
|
this.selectedFamily = family;
|
|
80
|
174
|
}
|
|
81
|
175
|
|
|
|
176
|
+ private sortFamiliesByHouseholder(families: Family[]): Family[] {
|
|
|
177
|
+ if (!this.danka) {
|
|
|
178
|
+ return families;
|
|
|
179
|
+ }
|
|
|
180
|
+
|
|
|
181
|
+ const householderName = this.normalizeName(this.danka.householder);
|
|
|
182
|
+
|
|
|
183
|
+ return [...families].sort((a, b) => {
|
|
|
184
|
+ const aIsHouseholder = this.normalizeName(a.name) === householderName;
|
|
|
185
|
+ const bIsHouseholder = this.normalizeName(b.name) === householderName;
|
|
|
186
|
+
|
|
|
187
|
+ if (aIsHouseholder === bIsHouseholder) {
|
|
|
188
|
+ return 0;
|
|
|
189
|
+ }
|
|
|
190
|
+
|
|
|
191
|
+ return aIsHouseholder ? -1 : 1;
|
|
|
192
|
+ });
|
|
|
193
|
+ }
|
|
|
194
|
+
|
|
|
195
|
+ private normalizeName(name: string): string {
|
|
|
196
|
+ return name.replace(/\s/g, '');
|
|
|
197
|
+ }
|
|
|
198
|
+
|
|
82
|
199
|
getFamilyById(id: string): Family | undefined {
|
|
83
|
200
|
if (!id) {
|
|
84
|
201
|
return undefined;
|