5 Коміти

Автор SHA1 Повідомлення Дата
  poohr e22fc1aa37 Merge branch 'develop' 3 тижднів тому
  poohr 8b605096a0 Merge remote-tracking branch 'origin/master' 3 тижднів тому
  poohr fdd9746ac2 [add] 3 тижднів тому
  poohr 3ed9dc93f2 Merge branch 'develop' 3 тижднів тому
  poohr 44f033cb93 [wip] 3 тижднів тому

+ 63
- 30
src/app/pages/danka-detail/danka-detail.scss Переглянути файл

2
   position: relative;
2
   position: relative;
3
   display: block;
3
   display: block;
4
   min-height: 100vh;
4
   min-height: 100vh;
5
-  background: #f4eee4;
5
+  background: #f6f0e7;
6
   color: #2f2720;
6
   color: #2f2720;
7
 }
7
 }
8
 
8
 
9
 .danka-detail-page {
9
 .danka-detail-page {
10
-  display: flex;
11
-  align-items: flex-start;
12
-  gap: 8px;
13
-  background: #f4eee4;
10
+  display: grid;
11
+  grid-template-columns: 172px minmax(0, 1fr);
12
+  gap: 20px;
13
+  padding: 0 38px 36px 0;
14
+  background: #f6f0e7;
14
 }
15
 }
15
 
16
 
16
 .danka-detail-main {
17
 .danka-detail-main {
17
-  flex: 1;
18
-  padding-right: 34px;
18
+  min-width: 0;
19
   box-sizing: border-box;
19
   box-sizing: border-box;
20
 }
20
 }
21
 
21
 
22
 .detail-panel {
22
 .detail-panel {
23
-  min-height: 650px;
24
-  padding: 26px 34px 36px;
25
-  background: #ffffff;
23
+  min-height: 760px;
24
+  padding: 34px 42px 40px;
25
+  background: #fffdf9;
26
   border: 2px solid #d8caba;
26
   border: 2px solid #d8caba;
27
-  border-radius: 76px;
27
+  border-radius: 64px;
28
   box-sizing: border-box;
28
   box-sizing: border-box;
29
 }
29
 }
30
 
30
 
32
   display: flex;
32
   display: flex;
33
   justify-content: space-between;
33
   justify-content: space-between;
34
   align-items: flex-start;
34
   align-items: flex-start;
35
-  margin-bottom: 20px;
35
+  gap: 24px;
36
+  margin-bottom: 22px;
36
 }
37
 }
37
 
38
 
38
 .page-title-row h1 {
39
 .page-title-row h1 {
39
-  margin: 0 0 8px;
40
+  margin: 0 0 18px;
40
   color: #2f2720;
41
   color: #2f2720;
41
-  font-size: 32px;
42
-  line-height: 1.2;
42
+  font-size: 34px;
43
+  line-height: 1.1;
43
   font-weight: 800;
44
   font-weight: 800;
44
-  letter-spacing: 0.02em;
45
+  letter-spacing: 0;
45
 }
46
 }
46
 
47
 
47
 .tab-list {
48
 .tab-list {
83
 .edit-button {
84
 .edit-button {
84
   width: 140px;
85
   width: 140px;
85
   height: 46px;
86
   height: 46px;
86
-  margin-top: 36px;
87
+  margin-top: 54px;
87
   border: 2px solid #8a6543;
88
   border: 2px solid #8a6543;
88
   border-radius: 6px;
89
   border-radius: 6px;
89
   background: #ffffff;
90
   background: #ffffff;
104
   padding: 14px 24px;
105
   padding: 14px 24px;
105
   border: 2px solid #d8caba;
106
   border: 2px solid #d8caba;
106
   border-radius: 8px;
107
   border-radius: 8px;
107
-  background: #f1e7d8;
108
+  background: #fbf7f0;
108
   display: flex;
109
   display: flex;
109
   align-items: center;
110
   align-items: center;
110
   box-sizing: border-box;
111
   box-sizing: border-box;
169
 .add-button {
170
 .add-button {
170
   width: 140px;
171
   width: 140px;
171
   height: 46px;
172
   height: 46px;
172
-  margin-top: 36px;
173
+  margin-top: 54px;
173
   border: 2px solid #8a6543;
174
   border: 2px solid #8a6543;
174
   border-radius: 6px;
175
   border-radius: 6px;
175
   background: #ffffff;
176
   background: #ffffff;
187
 .family-page-add-button {
188
 .family-page-add-button {
188
   width: 140px;
189
   width: 140px;
189
   height: 46px;
190
   height: 46px;
190
-  margin-top: 36px;
191
+  margin-top: 54px;
191
   border: 2px solid #8a6543;
192
   border: 2px solid #8a6543;
192
   border-radius: 6px;
193
   border-radius: 6px;
193
   background: #ffffff;
194
   background: #ffffff;
209
 .detail-content {
210
 .detail-content {
210
   display: grid;
211
   display: grid;
211
   grid-template-columns: minmax(0, 1fr) 420px;
212
   grid-template-columns: minmax(0, 1fr) 420px;
212
-  gap: 18px;
213
+  gap: 20px;
213
   align-items: start;
214
   align-items: start;
214
 }
215
 }
215
 
216
 
216
 .basic-info-section {
217
 .basic-info-section {
217
-  padding: 24px 20px 18px;
218
+  padding: 24px 20px 22px;
218
   border: 2px solid #d8caba;
219
   border: 2px solid #d8caba;
219
   border-radius: 12px;
220
   border-radius: 12px;
220
   background: #fffdf9;
221
   background: #fffdf9;
222
 }
223
 }
223
 
224
 
224
 .section-heading {
225
 .section-heading {
225
-  margin-bottom: 8px;
226
+  margin-bottom: 14px;
226
 }
227
 }
227
 
228
 
228
 .section-heading h2 {
229
 .section-heading h2 {
230
   color: #2f2720;
231
   color: #2f2720;
231
   font-size: 22px;
232
   font-size: 22px;
232
   font-weight: 800;
233
   font-weight: 800;
234
+  line-height: 1.3;
233
 }
235
 }
234
 
236
 
235
 .section-heading p {
237
 .section-heading p {
276
   border-radius: 6px;
278
   border-radius: 6px;
277
   background: #f3eee8;
279
   background: #f3eee8;
278
   color: #4b3c31;
280
   color: #4b3c31;
279
-  font-size: 17px;
281
+  font-size: 16px;
280
   font-weight: 800;
282
   font-weight: 800;
281
   display: flex;
283
   display: flex;
282
   align-items: center;
284
   align-items: center;
290
   border-radius: 0;
292
   border-radius: 0;
291
   background: transparent;
293
   background: transparent;
292
   color: #2f2720;
294
   color: #2f2720;
293
-  font-size: 17px;
295
+  font-size: 16px;
296
+  font-weight: 700;
294
   box-sizing: border-box;
297
   box-sizing: border-box;
295
   display: flex;
298
   display: flex;
296
   align-items: center;
299
   align-items: center;
390
   color: #2f2720;
393
   color: #2f2720;
391
   font-size: 22px;
394
   font-size: 22px;
392
   font-weight: 800;
395
   font-weight: 800;
396
+  line-height: 1.3;
393
   display: flex;
397
   display: flex;
394
   align-items: center;
398
   align-items: center;
395
   gap: 12px;
399
   gap: 12px;
452
 .next-memorial h3 {
456
 .next-memorial h3 {
453
   margin: 0 0 16px;
457
   margin: 0 0 16px;
454
   color: #4b3c31;
458
   color: #4b3c31;
455
-  font-size: 17px;
459
+  font-size: 18px;
456
   font-weight: 800;
460
   font-weight: 800;
457
   display: flex;
461
   display: flex;
458
   align-items: center;
462
   align-items: center;
535
 
539
 
536
   h2 {
540
   h2 {
537
     margin: 0;
541
     margin: 0;
538
-    font-size: 20px;
539
-    font-weight: 700;
542
+    font-size: 22px;
543
+    line-height: 1.3;
544
+    font-weight: 800;
540
   }
545
   }
541
 }
546
 }
542
 
547
 
808
 
813
 
809
   h2 {
814
   h2 {
810
     margin: 0;
815
     margin: 0;
811
-    font-size: 20px;
812
-    font-weight: 700;
816
+    font-size: 22px;
817
+    line-height: 1.3;
818
+    font-weight: 800;
813
   }
819
   }
814
 }
820
 }
815
 
821
 
1273
   color: #ffffff;
1279
   color: #ffffff;
1274
 }
1280
 }
1275
 
1281
 
1282
+@media (max-width: 1100px) {
1283
+  .danka-detail-page {
1284
+    grid-template-columns: 1fr;
1285
+    padding: 0 24px 32px;
1286
+  }
1287
+
1288
+  .detail-panel {
1289
+    min-height: auto;
1290
+    border-radius: 28px;
1291
+    padding: 28px 24px 32px;
1292
+  }
1293
+
1294
+  .detail-content {
1295
+    grid-template-columns: 1fr;
1296
+  }
1297
+
1298
+  .page-title-row {
1299
+    flex-direction: column;
1300
+  }
1301
+
1302
+  .edit-button,
1303
+  .add-button,
1304
+  .family-page-add-button {
1305
+    margin-top: 0;
1306
+  }
1307
+}
1308
+
1276
 /* 家族表が狭い画面では横スクロール */
1309
 /* 家族表が狭い画面では横スクロール */
1277
 @media (max-width: 800px) {
1310
 @media (max-width: 800px) {
1278
   .detail-content,
1311
   .detail-content,

+ 21
- 17
src/app/pages/danka-edit/danka-edit.html Переглянути файл

100
           <section class="phone-edit-section">
100
           <section class="phone-edit-section">
101
             <div class="section-heading">
101
             <div class="section-heading">
102
               <h2>電話番号(複数登録)</h2>
102
               <h2>電話番号(複数登録)</h2>
103
-              <p>番号と備考を複数登録できます。</p>
104
             </div>
103
             </div>
105
 
104
 
106
             <div formArrayName="phones" class="phone-table">
105
             <div formArrayName="phones" class="phone-table">
148
         </div>
147
         </div>
149
 
148
 
150
         <div class="bottom-actions">
149
         <div class="bottom-actions">
151
-          <button type="button" class="delete-button" (click)="deleteDanka()">
152
-            削除
153
-          </button>
154
-
155
-          <button type="button" class="cancel-button" [routerLink]="['/danka-detail', danka?.id]">
156
-            キャンセル
157
-          </button>
158
-
159
-          <button
160
-            type="button"
161
-            class="save-button"
162
-            [disabled]="dankaForm.invalid"
163
-            (click)="saveDanka()"
164
-          >
165
-            保存
166
-          </button>
150
+          <div class="left-actions"></div>
151
+
152
+          <div class="right-actions">
153
+            @if (danka) {
154
+              <button type="button" class="delete-button" (click)="deleteDanka()">
155
+                削除
156
+              </button>
157
+            }
158
+            <button type="button" class="cancel-button" [routerLink]="danka ? ['/danka-detail', danka.id] : ['/danka-list']">
159
+              キャンセル
160
+            </button>
161
+
162
+            <button
163
+              type="button"
164
+              class="save-button"
165
+              [disabled]="dankaForm.invalid"
166
+              (click)="saveDanka()"
167
+            >
168
+              保存
169
+            </button>
170
+          </div>
167
         </div>
171
         </div>
168
       </form>
172
       </form>
169
     </section>
173
     </section>

+ 37
- 16
src/app/pages/danka-edit/danka-edit.scss Переглянути файл

2
   position: relative;
2
   position: relative;
3
   display: block;
3
   display: block;
4
   min-height: 100vh;
4
   min-height: 100vh;
5
-  background: #f4eee4;
5
+  background: #f6f0e7;
6
   color: #2f2720;
6
   color: #2f2720;
7
 }
7
 }
8
 
8
 
11
   grid-template-columns: 172px minmax(0, 1fr);
11
   grid-template-columns: 172px minmax(0, 1fr);
12
   gap: 20px;
12
   gap: 20px;
13
   padding: 0 38px 36px 0;
13
   padding: 0 38px 36px 0;
14
-  background: #f4eee4;
14
+  background: #f6f0e7;
15
 }
15
 }
16
 
16
 
17
 .danka-edit-main {
17
 .danka-edit-main {
22
 .edit-panel {
22
 .edit-panel {
23
   min-height: 760px;
23
   min-height: 760px;
24
   padding: 34px 42px 40px;
24
   padding: 34px 42px 40px;
25
-  background: #ffffff;
25
+  background: #fffdf9;
26
   border: 2px solid #d8caba;
26
   border: 2px solid #d8caba;
27
   border-radius: 64px;
27
   border-radius: 64px;
28
   box-sizing: border-box;
28
   box-sizing: border-box;
55
 
55
 
56
 .edit-content {
56
 .edit-content {
57
   display: grid;
57
   display: grid;
58
-  grid-template-columns: minmax(0, 1fr) 500px;
59
-  gap: 32px;
58
+  grid-template-columns: minmax(0, 1fr) 430px;
59
+  gap: 22px;
60
   align-items: start;
60
   align-items: start;
61
 }
61
 }
62
 
62
 
63
 .basic-edit-section,
63
 .basic-edit-section,
64
 .phone-edit-section {
64
 .phone-edit-section {
65
-  padding-top: 0;
65
+  overflow: hidden;
66
+  padding: 0 28px 28px;
67
+  border: 2px solid #d8caba;
68
+  border-radius: 12px;
69
+  background: #fffdf9;
70
+  box-sizing: border-box;
66
 }
71
 }
67
 
72
 
68
 .basic-edit-section h2,
73
 .basic-edit-section h2,
69
 .phone-edit-section h2,
74
 .phone-edit-section h2,
70
 .support-box h2 {
75
 .support-box h2 {
71
-  margin: 0;
76
+  margin: 0 -28px 20px;
77
+  padding: 14px 28px;
78
+  background: #eadfce;
79
+  border-bottom: 2px solid #d8caba;
72
   color: #2f2720;
80
   color: #2f2720;
73
   font-size: 22px;
81
   font-size: 22px;
74
   line-height: 1.3;
82
   line-height: 1.3;
83
 
91
 
84
 /* 基本情報 */
92
 /* 基本情報 */
85
 .form-list {
93
 .form-list {
86
-  margin-top: 12px;
94
+  margin-top: 0;
95
+  padding-top: 18px;
96
+  border-top: 2px solid #eadfce;
87
 }
97
 }
88
 
98
 
89
 .form-field {
99
 .form-field {
94
 
104
 
95
 .form-row {
105
 .form-row {
96
   display: grid;
106
   display: grid;
97
-  grid-template-columns: 140px 1fr;
107
+  grid-template-columns: 132px 1fr;
98
   align-items: center;
108
   align-items: center;
99
-  gap: 14px;
100
-  margin-bottom: 12px;
109
+  gap: 18px;
110
+  margin-bottom: 14px;
101
 }
111
 }
102
 
112
 
103
 .form-row label {
113
 .form-row label {
124
   padding: 0 14px;
134
   padding: 0 14px;
125
 }
135
 }
126
 
136
 
137
+.form-row:has(#postalCode) input {
138
+  max-width: 300px;
139
+}
140
+
127
 .form-row textarea {
141
 .form-row textarea {
128
-  min-height: 104px;
142
+  min-height: 150px;
129
   padding: 12px 14px;
143
   padding: 12px 14px;
130
   line-height: 1.6;
144
   line-height: 1.6;
131
   resize: vertical;
145
   resize: vertical;
157
 .phone-table-header,
171
 .phone-table-header,
158
 .phone-table-row {
172
 .phone-table-row {
159
   display: grid;
173
   display: grid;
160
-  grid-template-columns: 1.35fr 1.45fr 84px;
174
+  grid-template-columns: minmax(110px, 1fr) minmax(88px, 0.8fr) 72px;
161
   align-items: center;
175
   align-items: center;
162
   gap: 10px;
176
   gap: 10px;
163
 }
177
 }
235
 .phone-action {
249
 .phone-action {
236
   display: flex;
250
   display: flex;
237
   justify-content: flex-end;
251
   justify-content: flex-end;
238
-  margin-top: 10px;
252
+  margin-top: 16px;
239
 }
253
 }
240
 
254
 
241
 .add-phone-button {
255
 .add-phone-button {
277
 /* 下部ボタン */
291
 /* 下部ボタン */
278
 .bottom-actions {
292
 .bottom-actions {
279
   display: flex;
293
   display: flex;
280
-  justify-content: flex-end;
294
+  justify-content: space-between;
295
+  align-items: center;
296
+  gap: 12px;
297
+  margin-top: 36px;
298
+}
299
+
300
+.left-actions,
301
+.right-actions {
302
+  display: flex;
281
   align-items: center;
303
   align-items: center;
282
   gap: 12px;
304
   gap: 12px;
283
-  margin-top: 26px;
284
 }
305
 }
285
 
306
 
286
 .delete-button,
307
 .delete-button,

+ 19
- 25
src/app/pages/dashboard/dashboard.html Переглянути файл

46
           <div>
46
           <div>
47
             <h2>最近開いた檀家・世帯</h2>
47
             <h2>最近開いた檀家・世帯</h2>
48
           </div>
48
           </div>
49
-          <a class="text-link" href="#">一覧へ</a>
50
         </div>
49
         </div>
51
 
50
 
52
         <div class="recent-table" role="table" aria-label="最近開いた檀家">
51
         <div class="recent-table" role="table" aria-label="最近開いた檀家">
58
             <div class="cell" role="columnheader">最終更新</div>
57
             <div class="cell" role="columnheader">最終更新</div>
59
           </div>
58
           </div>
60
 
59
 
61
-          <a class="recent-row" href="#" role="row">
62
-            <div class="cell" role="cell">鈴木 太郎</div>
63
-            <div class="cell muted" role="cell">すずき</div>
64
-            <div class="cell" role="cell">市内 1-2-3</div>
65
-            <div class="cell" role="cell">6月12日</div>
66
-            <div class="cell muted" role="cell">今日</div>
67
-          </a>
68
-
69
-          <a class="recent-row" href="#" role="row">
70
-            <div class="cell" role="cell">佐藤 恵一</div>
71
-            <div class="cell muted" role="cell">さとう</div>
72
-            <div class="cell" role="cell">市内 2-8-1</div>
73
-            <div class="cell" role="cell">7月4日</div>
74
-            <div class="cell muted" role="cell">昨日</div>
75
-          </a>
76
-
77
-          <a class="recent-row" href="#" role="row">
78
-            <div class="cell" role="cell">田中 雪子</div>
79
-            <div class="cell muted" role="cell">たなか</div>
80
-            <div class="cell" role="cell">市内 3-4-6</div>
81
-            <div class="cell muted" role="cell">未設定</div>
82
-            <div class="cell muted" role="cell">5日前</div>
83
-          </a>
60
+          @if (recentDankaList.length > 0) {
61
+            @for (recent of recentDankaList; track recent.danka.id) {
62
+              <a class="recent-row" [routerLink]="['/danka-detail', recent.danka.id]" role="row">
63
+                <div class="cell" role="cell">{{ recent.danka.householder }}</div>
64
+                <div class="cell muted" role="cell">{{ recent.danka.householderFurigana }}</div>
65
+                <div class="cell" role="cell">{{ recent.danka.address }}</div>
66
+                <div class="cell" role="cell">{{ recent.nextMemorialLabel }}</div>
67
+                <div class="cell muted" role="cell">{{ recent.updatedAtLabel }}</div>
68
+              </a>
69
+            }
70
+          } @else {
71
+            <div class="recent-row" role="row">
72
+              <div class="cell muted" role="cell">表示できる檀家・世帯はありません</div>
73
+              <div class="cell muted" role="cell">-</div>
74
+              <div class="cell muted" role="cell">-</div>
75
+              <div class="cell muted" role="cell">-</div>
76
+              <div class="cell muted" role="cell">-</div>
77
+            </div>
78
+          }
84
         </div>
79
         </div>
85
       </section>
80
       </section>
86
 
81
 
89
           <div>
84
           <div>
90
             <h2>近日の法要・命日</h2>
85
             <h2>近日の法要・命日</h2>
91
           </div>
86
           </div>
92
-          <a class="text-link" href="#">年次法要一覧へ</a>
93
         </div>
87
         </div>
94
 
88
 
95
         <div class="upcoming-list">
89
         <div class="upcoming-list">

+ 65
- 0
src/app/pages/dashboard/dashboard.ts Переглянути файл

2
 import { RouterLink } from '@angular/router';
2
 import { RouterLink } from '@angular/router';
3
 import { KakochoService } from '../../services/kakocho-service';
3
 import { KakochoService } from '../../services/kakocho-service';
4
 import { DankaService } from '../../services/dankaService';
4
 import { DankaService } from '../../services/dankaService';
5
+import { Danka } from '../../models/danka';
5
 import { AppHeader } from '../../share/header/app-header';
6
 import { AppHeader } from '../../share/header/app-header';
6
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
7
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
7
 
8
 
16
   status: '準備確認' | '要確認';
17
   status: '準備確認' | '要確認';
17
 }
18
 }
18
 
19
 
20
+interface RecentDanka {
21
+  danka: Danka;
22
+  nextMemorialLabel: string;
23
+  updatedAtLabel: string;
24
+}
25
+
19
 @Component({
26
 @Component({
20
   selector: 'app-dashboard',
27
   selector: 'app-dashboard',
21
   imports: [AppHeader, AppSideMenu, RouterLink],
28
   imports: [AppHeader, AppSideMenu, RouterLink],
27
   todayMemorialCount = 0;
34
   todayMemorialCount = 0;
28
   upcomingWeeklyMemorialCount = 0;
35
   upcomingWeeklyMemorialCount = 0;
29
   monthlyMemorialCount = 0;
36
   monthlyMemorialCount = 0;
37
+  recentDankaList: RecentDanka[] = [];
30
   upcomingMemorials: UpcomingMemorial[] = [];
38
   upcomingMemorials: UpcomingMemorial[] = [];
31
 
39
 
32
   private readonly targetYear = new Date().getFullYear();
40
   private readonly targetYear = new Date().getFullYear();
37
   ) {
45
   ) {
38
     this.setWeeklyMemorialSummary();
46
     this.setWeeklyMemorialSummary();
39
     this.setMonthlyMemorialSummary();
47
     this.setMonthlyMemorialSummary();
48
+    this.setRecentDankaList();
40
     this.setUpcomingMemorials();
49
     this.setUpcomingMemorials();
41
   }
50
   }
42
 
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
+    }));
58
+  }
59
+
43
   private setWeeklyMemorialSummary(): void {
60
   private setWeeklyMemorialSummary(): void {
44
     const today = this.toDateOnly(new Date());
61
     const today = this.toDateOnly(new Date());
45
     const weekEnd = this.addDays(this.getWeekStart(today), 6);
62
     const weekEnd = this.addDays(this.getWeekStart(today), 6);
150
     return `${date.getMonth() + 1}月${date.getDate()}日`;
167
     return `${date.getMonth() + 1}月${date.getDate()}日`;
151
   }
168
   }
152
 
169
 
170
+  private getNextMemorialLabel(dankaId: string): string {
171
+    const today = this.toDateOnly(new Date());
172
+    const nextMemorial = this.kakochoService
173
+      .getKakochoByDankaId(dankaId)
174
+      .map((kakocho) => {
175
+        const deathDate = this.parseDate(kakocho.deathDate);
176
+        if (!deathDate) {
177
+          return null;
178
+        }
179
+
180
+        const memorialDate = new Date(this.targetYear, deathDate.getMonth(), deathDate.getDate());
181
+        if (memorialDate < today || !this.getMemorialType(deathDate)) {
182
+          return null;
183
+        }
184
+
185
+        return memorialDate;
186
+      })
187
+      .filter((date): date is Date => date !== null)
188
+      .sort((a, b) => a.getTime() - b.getTime())[0];
189
+
190
+    return nextMemorial ? this.formatDateLabel(nextMemorial, today) : '未設定';
191
+  }
192
+
193
+  private formatUpdatedAt(updatedAt: string): string {
194
+    const updatedDate = this.parseDate(updatedAt);
195
+    const today = this.toDateOnly(new Date());
196
+
197
+    if (!updatedDate) {
198
+      return '未登録';
199
+    }
200
+
201
+    const diffDays = Math.floor((today.getTime() - updatedDate.getTime()) / 86400000);
202
+
203
+    if (diffDays === 0) {
204
+      return '今日';
205
+    }
206
+
207
+    if (diffDays === 1) {
208
+      return '昨日';
209
+    }
210
+
211
+    if (diffDays > 1 && diffDays <= 7) {
212
+      return `${diffDays}日前`;
213
+    }
214
+
215
+    return `${updatedDate.getMonth() + 1}月${updatedDate.getDate()}日`;
216
+  }
217
+
153
   private getWeekStart(date: Date): Date {
218
   private getWeekStart(date: Date): Date {
154
     const day = date.getDay();
219
     const day = date.getDay();
155
     const diff = day === 0 ? -6 : 1 - day;
220
     const diff = day === 0 ? -6 : 1 - day;

+ 16
- 18
src/app/pages/family-edit/family-edit.html Переглянути файл

86
                 </div>
86
                 </div>
87
               </div>
87
               </div>
88
 
88
 
89
-              <div class="form-row form-row-heading">
90
-                <label></label>
89
+              <div class="form-row householder-setting-row">
90
+                <label>施主設定</label>
91
                 <div class="form-field">
91
                 <div class="form-field">
92
-                  <h3 class="sub-section-title">家系図情報</h3>
93
-                  <p class="sub-section-description">
94
-                    家系図に反映する親子・配偶者の関係を設定します。
95
-                  </p>
92
+                  <button type="button"
93
+                          class="set-householder-button"
94
+                          (click)="setAsHouseholder()">
95
+                    この方を施主にする
96
+                  </button>
96
                 </div>
97
                 </div>
97
               </div>
98
               </div>
99
+            </div>
100
+          </section>
98
 
101
 
102
+          <section class="family-tree-edit-section">
103
+            <h2>家系図情報</h2>
104
+            <p class="section-description">
105
+              家系図に反映する親子・配偶者の関係を設定します。
106
+            </p>
107
+
108
+            <div class="form-list">
99
               <div class="form-row">
109
               <div class="form-row">
100
                 <label for="fatherId">父</label>
110
                 <label for="fatherId">父</label>
101
                 <div class="form-field">
111
                 <div class="form-field">
167
 
177
 
168
             </div>
178
             </div>
169
           </section>
179
           </section>
170
-
171
-          <section class="phone-edit-section">
172
-            <div class="householder-area">
173
-              <h3>この方を施主にする</h3>
174
-
175
-              <button type="button"
176
-                      class="set-householder-button"
177
-                      (click)="setAsHouseholder()">
178
-                施主に設定
179
-              </button>
180
-            </div>
181
-          </section>
182
         </div>
180
         </div>
183
 
181
 
184
         <div class="bottom-actions">
182
         <div class="bottom-actions">

+ 32
- 55
src/app/pages/family-edit/family-edit.scss Переглянути файл

2
   position: relative;
2
   position: relative;
3
   display: block;
3
   display: block;
4
   min-height: 100vh;
4
   min-height: 100vh;
5
-  background: #f4eee4;
5
+  background: #f6f0e7;
6
   color: #2f2720;
6
   color: #2f2720;
7
 }
7
 }
8
 
8
 
11
   grid-template-columns: 172px minmax(0, 1fr);
11
   grid-template-columns: 172px minmax(0, 1fr);
12
   gap: 20px;
12
   gap: 20px;
13
   padding: 0 38px 36px 0;
13
   padding: 0 38px 36px 0;
14
-  background: #f4eee4;
14
+  background: #f6f0e7;
15
 }
15
 }
16
 
16
 
17
 .danka-edit-main {
17
 .danka-edit-main {
22
 .edit-panel {
22
 .edit-panel {
23
   min-height: 760px;
23
   min-height: 760px;
24
   padding: 34px 42px 40px;
24
   padding: 34px 42px 40px;
25
-  background: #ffffff;
25
+  background: #fffdf9;
26
   border: 2px solid #d8caba;
26
   border: 2px solid #d8caba;
27
   border-radius: 64px;
27
   border-radius: 64px;
28
   box-sizing: border-box;
28
   box-sizing: border-box;
56
 
56
 
57
 .edit-content {
57
 .edit-content {
58
   display: grid;
58
   display: grid;
59
-  grid-template-columns: minmax(0, 1fr) 500px;
60
-  gap: 32px;
59
+  grid-template-columns: 1fr;
60
+  gap: 16px;
61
   align-items: start;
61
   align-items: start;
62
 }
62
 }
63
 
63
 
64
-.basic-edit-section {
65
-  padding-left: 0;
64
+.basic-edit-section,
65
+.family-tree-edit-section {
66
+  overflow: hidden;
67
+  padding: 0 22px 24px;
68
+  border: 2px solid #d8caba;
69
+  border-radius: 12px;
70
+  background: #fffdf9;
71
+  box-sizing: border-box;
66
 }
72
 }
67
 
73
 
68
 .basic-edit-section h2,
74
 .basic-edit-section h2,
75
+.family-tree-edit-section h2,
69
 .section-heading h2 {
76
 .section-heading h2 {
70
-  margin: 0;
77
+  margin: 0 -22px 18px;
78
+  padding: 12px 22px;
79
+  background: #eadfce;
80
+  border-bottom: 2px solid #d8caba;
71
   color: #2f2720;
81
   color: #2f2720;
72
   font-size: 22px;
82
   font-size: 22px;
73
   line-height: 1.3;
83
   line-height: 1.3;
84
   font-size: 14px;
94
   font-size: 14px;
85
 }
95
 }
86
 
96
 
97
+.section-description {
98
+  margin: 6px 0 0;
99
+  color: #7b6b5c;
100
+  font-size: 14px;
101
+  line-height: 1.6;
102
+}
103
+
87
 .form-list {
104
 .form-list {
88
-  width: 100%;
89
-  margin-top: 12px;
105
+  width: min(100%, 620px);
106
+  margin-top: 14px;
90
 }
107
 }
91
 
108
 
92
 .form-row {
109
 .form-row {
93
   display: grid;
110
   display: grid;
94
-  grid-template-columns: 140px 1fr;
111
+  grid-template-columns: 150px minmax(0, 1fr);
95
   align-items: center;
112
   align-items: center;
96
   gap: 14px;
113
   gap: 14px;
97
   margin-bottom: 12px;
114
   margin-bottom: 12px;
129
 }
146
 }
130
 
147
 
131
 .form-row textarea {
148
 .form-row textarea {
132
-  min-height: 104px;
149
+  min-height: 112px;
133
   padding: 12px 14px;
150
   padding: 12px 14px;
134
   resize: vertical;
151
   resize: vertical;
135
   line-height: 1.6;
152
   line-height: 1.6;
178
   line-height: 1.6;
195
   line-height: 1.6;
179
 }
196
 }
180
 
197
 
181
-.phone-edit-section {
182
-  min-height: 240px;
183
-  padding: 18px 20px;
184
-  border: 2px solid #d8caba;
185
-  border-radius: 8px;
186
-  background: #fffdf9;
187
-  box-sizing: border-box;
188
-}
189
-
190
-.family-edit-guide {
191
-  padding: 18px 22px;
192
-  border: 2px solid #d8caba;
193
-  border-radius: 14px;
194
-  background: #ffffff;
195
-  box-sizing: border-box;
196
-}
197
-
198
-.family-edit-guide ul {
199
-  margin: 0;
200
-  padding-left: 20px;
201
-  color: #7b6b5c;
202
-  font-size: 15px;
203
-  line-height: 2;
204
-}
205
-
206
-.householder-area {
207
-  margin-top: 0;
208
-  padding: 18px 20px;
209
-  border: 2px solid #d8caba;
210
-  border-radius: 8px;
211
-  background: #eadfce;
212
-  box-sizing: border-box;
213
-}
214
-
215
-.householder-area h3 {
216
-  margin: 0 0 12px;
217
-  color: #2f2720;
218
-  font-size: 17px;
219
-  font-weight: 800;
220
-}
221
-
222
 .set-householder-button {
198
 .set-householder-button {
223
-  width: 148px;
199
+  width: auto;
200
+  min-width: 170px;
224
   height: 46px;
201
   height: 46px;
225
   border: 2px solid #d8caba;
202
   border: 2px solid #d8caba;
226
   border-radius: 6px;
203
   border-radius: 6px;
241
   justify-content: flex-end;
218
   justify-content: flex-end;
242
   align-items: center;
219
   align-items: center;
243
   gap: 12px;
220
   gap: 12px;
244
-  margin-top: 26px;
221
+  margin-top: 28px;
245
 }
222
 }
246
 
223
 
247
 .delete-button,
224
 .delete-button,

+ 31
- 1
src/app/pages/family-edit/family-edit.ts Переглянути файл

9
 import { ActivatedRoute, Router, RouterLink } from '@angular/router';
9
 import { ActivatedRoute, Router, RouterLink } from '@angular/router';
10
 import { AppHeader } from '../../share/header/app-header';
10
 import { AppHeader } from '../../share/header/app-header';
11
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
11
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
12
+import { DankaService } from '../../services/dankaService';
12
 import { FamilyService } from '../../services/family-service';
13
 import { FamilyService } from '../../services/family-service';
13
 import { MarriageRelationService } from '../../services/marriage-relation-service';
14
 import { MarriageRelationService } from '../../services/marriage-relation-service';
14
 import { Danka } from '../../models/danka';
15
 import { Danka } from '../../models/danka';
30
   relationMode: string = '';
31
   relationMode: string = '';
31
   baseFamilyId: string = '';
32
   baseFamilyId: string = '';
32
   marriageErrorMessages: string[] = [];
33
   marriageErrorMessages: string[] = [];
34
+  private setHouseholderOnSave = false;
33
 
35
 
34
   constructor(
36
   constructor(
37
+    private dankaService: DankaService,
35
     private familyService: FamilyService,
38
     private familyService: FamilyService,
36
     private marriageRelationService: MarriageRelationService,
39
     private marriageRelationService: MarriageRelationService,
37
     private route: ActivatedRoute,
40
     private route: ActivatedRoute,
39
   ) {
42
   ) {
40
     this.dankaId = this.route.snapshot.params['dankaId'];
43
     this.dankaId = this.route.snapshot.params['dankaId'];
41
     this.familyId = this.route.snapshot.params['familyId'];
44
     this.familyId = this.route.snapshot.params['familyId'];
45
+    this.danka = this.dankaService.getDankaById(this.dankaId);
42
     this.families = this.familyService.getFamiliesByDankaId(this.dankaId);
46
     this.families = this.familyService.getFamiliesByDankaId(this.dankaId);
43
     this.relationMode = this.route.snapshot.queryParamMap.get('relationMode') ?? '';
47
     this.relationMode = this.route.snapshot.queryParamMap.get('relationMode') ?? '';
44
     this.baseFamilyId = this.route.snapshot.queryParamMap.get('baseFamilyId') ?? '';
48
     this.baseFamilyId = this.route.snapshot.queryParamMap.get('baseFamilyId') ?? '';
193
     }
197
     }
194
 
198
 
195
     this.familyService.saveFamily(updatedFamily);
199
     this.familyService.saveFamily(updatedFamily);
200
+    this.saveHouseholderIfSelected(updatedFamily);
196
     this.router.navigate(['/danka-detail', dankaId], { queryParams: { tab: 'family' } });
201
     this.router.navigate(['/danka-detail', dankaId], { queryParams: { tab: 'family' } });
197
   }
202
   }
198
 
203
 
210
     this.router.navigate(['/danka-detail', dankaId], { queryParams: { tab: 'family' } });
215
     this.router.navigate(['/danka-detail', dankaId], { queryParams: { tab: 'family' } });
211
   }
216
   }
212
 
217
 
213
-  setAsHouseholder() {}
218
+  setAsHouseholder(): void {
219
+    this.setHouseholderOnSave = true;
220
+    this.familyForm.patchValue({
221
+      relationship: '施主',
222
+    });
223
+  }
224
+
225
+  private saveHouseholderIfSelected(family: Family): void {
226
+    if (!this.setHouseholderOnSave || !this.danka) {
227
+      return;
228
+    }
229
+
230
+    this.dankaService.saveDanka({
231
+      ...this.danka,
232
+      householder: family.name,
233
+      householderFurigana: family.furigana,
234
+      updatedAt: this.formatDateForSave(new Date()),
235
+    });
236
+  }
237
+
238
+  private formatDateForSave(date: Date): string {
239
+    const year = date.getFullYear();
240
+    const month = String(date.getMonth() + 1).padStart(2, '0');
241
+    const day = String(date.getDate()).padStart(2, '0');
242
+    return `${year}-${month}-${day}`;
243
+  }
214
 }
244
 }

+ 17
- 8
src/app/pages/kakocho-edit/kakocho-edit.scss Переглянути файл

2
   position: relative;
2
   position: relative;
3
   display: block;
3
   display: block;
4
   min-height: 100vh;
4
   min-height: 100vh;
5
-  background: #f4eee4;
5
+  background: #f6f0e7;
6
   color: #2f2720;
6
   color: #2f2720;
7
 }
7
 }
8
 
8
 
11
   grid-template-columns: 172px minmax(0, 1fr);
11
   grid-template-columns: 172px minmax(0, 1fr);
12
   gap: 20px;
12
   gap: 20px;
13
   padding: 0 38px 36px 0;
13
   padding: 0 38px 36px 0;
14
-  background: #f4eee4;
14
+  background: #f6f0e7;
15
 }
15
 }
16
 
16
 
17
 .danka-edit-main {
17
 .danka-edit-main {
22
 .edit-panel {
22
 .edit-panel {
23
   min-height: 760px;
23
   min-height: 760px;
24
   padding: 34px 42px 40px;
24
   padding: 34px 42px 40px;
25
-  background: #ffffff;
25
+  background: #fffdf9;
26
   border: 2px solid #d8caba;
26
   border: 2px solid #d8caba;
27
   border-radius: 64px;
27
   border-radius: 64px;
28
   box-sizing: border-box;
28
   box-sizing: border-box;
55
 
55
 
56
 .edit-content {
56
 .edit-content {
57
   display: grid;
57
   display: grid;
58
-  grid-template-columns: minmax(0, 1fr) 500px;
59
-  gap: 32px;
58
+  grid-template-columns: minmax(0, 1fr);
59
+  gap: 22px;
60
   align-items: start;
60
   align-items: start;
61
 }
61
 }
62
 
62
 
63
 .basic-edit-section,
63
 .basic-edit-section,
64
 .phone-edit-section {
64
 .phone-edit-section {
65
-  padding-top: 0;
65
+  overflow: hidden;
66
+  padding: 0 28px 28px;
67
+  border: 2px solid #d8caba;
68
+  border-radius: 12px;
69
+  background: #fffdf9;
70
+  box-sizing: border-box;
66
 }
71
 }
67
 
72
 
68
 .basic-edit-section h2,
73
 .basic-edit-section h2,
69
 .phone-edit-section h2,
74
 .phone-edit-section h2,
70
 .support-box h2 {
75
 .support-box h2 {
71
-  margin: 0;
76
+  margin: 0 -28px 20px;
77
+  padding: 14px 28px;
78
+  background: #eadfce;
79
+  border-bottom: 2px solid #d8caba;
72
   color: #2f2720;
80
   color: #2f2720;
73
   font-size: 22px;
81
   font-size: 22px;
74
   line-height: 1.3;
82
   line-height: 1.3;
83
 
91
 
84
 /* 蝓コ譛ャ諠・ア */
92
 /* 蝓コ譛ャ諠・ア */
85
 .form-list {
93
 .form-list {
86
-  margin-top: 12px;
94
+  width: min(100%, 980px);
95
+  margin-top: 0;
87
 }
96
 }
88
 
97
 
89
 .form-field {
98
 .form-field {

+ 4
- 0
src/app/pages/kakocho-edit/kakocho-edit.ts Переглянути файл

146
       this.kakochoService.addKakocho(
146
       this.kakochoService.addKakocho(
147
         newKakocho
147
         newKakocho
148
       );
148
       );
149
+
150
+      if (this.sourceFamily) {
151
+        this.familyService.deleteFamily(this.sourceFamily.id);
152
+      }
149
     }
153
     }
150
 
154
 
151
     // 一覧へ戻る
155
     // 一覧へ戻る

+ 32
- 1
src/app/services/dankaService.ts Переглянути файл

17
 })
17
 })
18
 export class DankaService {
18
 export class DankaService {
19
   private path = 'danka';
19
   private path = 'danka';
20
+  private readonly recentDankaStorageKey = 'kaimyo-management.recent-danka';
20
 
21
 
21
   // 一覧
22
   // 一覧
22
   async getDankaList(): Promise<Danka[]> {
23
   async getDankaList(): Promise<Danka[]> {
58
     const ref = doc(db, this.path, id);
59
     const ref = doc(db, this.path, id);
59
     await deleteDoc(ref);
60
     await deleteDoc(ref);
60
   }
61
   }
61
-}
62
+
63
+  private getRecentDankaIds(): string[] {
64
+    if (!this.canUseLocalStorage()) {
65
+      return [];
66
+    }
67
+
68
+    const value = localStorage.getItem(this.recentDankaStorageKey);
69
+    if (!value) {
70
+      return [];
71
+    }
72
+
73
+    try {
74
+      const parsed = JSON.parse(value);
75
+      return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];
76
+    } catch {
77
+      return [];
78
+    }
79
+  }
80
+
81
+  private saveRecentDankaIds(ids: string[]): void {
82
+    if (!this.canUseLocalStorage()) {
83
+      return;
84
+    }
85
+
86
+    localStorage.setItem(this.recentDankaStorageKey, JSON.stringify(ids));
87
+  }
88
+
89
+  private canUseLocalStorage(): boolean {
90
+    return typeof localStorage !== 'undefined';
91
+  }
92
+}

Завантаження…
Відмінити
Зберегти