Skip to content

Commit e47e08f

Browse files
Refactor codebase: add shared services, context managers, and utilities
- Add JavaScript utilities: api.js (centralized API client), constants.js, dom.js (DOM helpers), serviceHelpers.js (CRUD patterns) - Refactor providers.js and familyMembers.js to use shared helpers - Add Python db_connection() and db_readonly() context managers - Create SimpleEntityService for generic CRUD operations - Create FileService for shared file upload/delete operations - Refactor attachments.py and plan_year_documents.py to use new services - Consolidate CSS badges using CSS variables - Fix receipt icon disappearing after attachment upload 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 73e8e95 commit e47e08f

File tree

19 files changed

+1252
-709
lines changed

19 files changed

+1252
-709
lines changed
Lines changed: 88 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,231 +1,160 @@
11
/* Badge Styles */
22

3-
/* ===== Badges ===== */
4-
.badge {
5-
display: inline-block;
6-
padding: var(--spacing-xs) var(--spacing-md);
7-
border-radius: var(--radius-sm);
8-
font-size: var(--text-sm);
9-
font-weight: 600;
10-
}
11-
12-
.badge-hsa {
13-
background-color: rgba(59, 130, 246, 0.15);
14-
color: var(--primary-blue);
15-
}
16-
17-
.badge-fsa {
18-
background-color: rgba(16, 185, 129, 0.15);
19-
color: var(--primary-green);
20-
}
21-
22-
.badge-dcfsa {
23-
background-color: rgba(139, 92, 246, 0.15);
24-
color: var(--primary-purple);
25-
}
26-
27-
/* ===== Status Badges ===== */
28-
.status {
3+
/* ===== Base Badge Styles ===== */
4+
.badge,
5+
.status,
6+
.status-badge,
7+
.account-badge,
8+
.policy-type-badge,
9+
.account-type-badge {
2910
display: inline-block;
3011
padding: var(--spacing-xs) var(--spacing-md);
3112
border-radius: var(--radius-sm);
3213
font-size: var(--text-sm);
3314
font-weight: 600;
15+
white-space: nowrap;
3416
}
3517

36-
.status-open {
37-
background-color: rgba(59, 130, 246, 0.15);
38-
color: var(--primary-blue);
39-
}
40-
41-
.status-submitted {
42-
background-color: rgba(245, 158, 11, 0.15);
43-
color: var(--warning-amber);
44-
}
45-
46-
.status-pending {
47-
background-color: rgba(245, 158, 11, 0.15);
48-
color: var(--warning-amber);
49-
}
50-
51-
.status-partially-reimbursed {
52-
background-color: rgba(139, 92, 246, 0.15);
53-
color: var(--primary-purple);
54-
}
55-
56-
.status-reimbursed {
57-
background-color: rgba(16, 185, 129, 0.15);
58-
color: var(--success-green);
59-
}
60-
61-
.status-rejected {
62-
background-color: rgba(239, 68, 68, 0.15);
63-
color: var(--danger-red-light);
64-
}
65-
66-
.status-disputed {
67-
background-color: rgba(245, 158, 11, 0.15);
68-
color: var(--warning-amber);
69-
}
70-
71-
.status-closed {
72-
background: rgba(107, 114, 128, 0.15);
73-
color: var(--neutral-gray);
74-
}
75-
76-
/* Account/Policy Type Badges - Unified Badge System */
18+
/* Smaller variant for account/policy badges */
7719
.account-badge,
7820
.policy-type-badge,
79-
.account-type-badge {
80-
display: inline-block;
21+
.account-type-badge,
22+
.status-badge {
8123
padding: var(--spacing-xs) 0.65rem;
8224
border-radius: 6px;
8325
font-size: var(--text-xs);
8426
font-weight: 700;
85-
white-space: nowrap;
8627
}
8728

88-
/* Single Account Type Badges */
89-
.account-hsa,
29+
/* ===== Category/Account Type Badges ===== */
30+
/* HSA - Blue */
9031
.badge-hsa,
32+
.account-hsa,
9133
.hsa-badge {
92-
background: rgba(59, 130, 246, 0.15);
34+
background-color: var(--bg-hsa);
9335
color: var(--primary-blue);
9436
}
9537

96-
.account-fsa,
97-
.badge-fsa,
98-
.fsa-badge {
99-
background: rgba(16, 185, 129, 0.15);
100-
color: var(--primary-green);
101-
}
102-
103-
.account-dcfsa,
104-
.badge-dcfsa,
105-
.dcfsa-badge {
106-
background: rgba(139, 92, 246, 0.15);
107-
color: var(--primary-purple);
108-
}
109-
110-
/* Combined Account Type Badges (HSA+DCFSA, FSA+DCFSA) */
111-
.badge-hsa-dcfsa {
112-
background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(139, 92, 246, 0.15) 100%);
113-
color: var(--primary-blue);
114-
}
115-
116-
.badge-fsa-dcfsa {
117-
background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(139, 92, 246, 0.15) 100%);
118-
color: var(--primary-green);
119-
}
120-
121-
/* Dark Mode - Single Types */
122-
html.dark-mode .account-hsa,
12338
html.dark-mode .badge-hsa,
39+
html.dark-mode .account-hsa,
12440
html.dark-mode .hsa-badge {
125-
background: rgba(59, 130, 246, 0.25);
12641
color: var(--primary-blue-light);
12742
}
12843

129-
html.dark-mode .account-fsa,
44+
/* FSA - Green */
45+
.badge-fsa,
46+
.account-fsa,
47+
.fsa-badge {
48+
background-color: var(--bg-fsa);
49+
color: var(--primary-green);
50+
}
51+
13052
html.dark-mode .badge-fsa,
53+
html.dark-mode .account-fsa,
13154
html.dark-mode .fsa-badge {
132-
background: rgba(16, 185, 129, 0.25);
13355
color: var(--primary-green-light);
13456
}
13557

136-
html.dark-mode .account-dcfsa,
58+
/* DCFSA - Purple */
59+
.badge-dcfsa,
60+
.account-dcfsa,
61+
.dcfsa-badge {
62+
background-color: var(--bg-dcfsa);
63+
color: var(--primary-purple);
64+
}
65+
13766
html.dark-mode .badge-dcfsa,
67+
html.dark-mode .account-dcfsa,
13868
html.dark-mode .dcfsa-badge {
139-
background: rgba(139, 92, 246, 0.25);
14069
color: var(--primary-purple-light);
14170
}
14271

143-
/* Dark Mode - Combined Types */
72+
/* Combined Account Type Badges */
73+
.badge-hsa-dcfsa {
74+
background: linear-gradient(135deg, var(--bg-hsa) 0%, var(--bg-dcfsa) 100%);
75+
color: var(--primary-blue);
76+
}
77+
14478
html.dark-mode .badge-hsa-dcfsa {
145-
background: linear-gradient(135deg, rgba(59, 130, 246, 0.25) 0%, rgba(139, 92, 246, 0.25) 100%);
14679
color: var(--primary-blue-light);
14780
}
14881

149-
html.dark-mode .badge-fsa-dcfsa {
150-
background: linear-gradient(135deg, rgba(16, 185, 129, 0.25) 0%, rgba(139, 92, 246, 0.25) 100%);
151-
color: var(--primary-green-light);
82+
.badge-fsa-dcfsa {
83+
background: linear-gradient(135deg, var(--bg-fsa) 0%, var(--bg-dcfsa) 100%);
84+
color: var(--primary-green);
15285
}
15386

154-
/* Status Badges - Colorful and Modern */
155-
.status-badge {
156-
display: inline-block;
157-
padding: var(--spacing-xs) 0.65rem;
158-
border-radius: 6px;
159-
font-size: var(--text-xs);
160-
font-weight: 600;
87+
html.dark-mode .badge-fsa-dcfsa {
88+
color: var(--primary-green-light);
16189
}
16290

91+
/* ===== Status Badges ===== */
92+
/* Open - Blue */
93+
.status-open,
16394
.status-badge.status-open {
164-
background: rgba(59, 130, 246, 0.15);
95+
background-color: var(--bg-hsa);
16596
color: var(--primary-blue);
16697
}
16798

168-
.status-badge.status-pending {
169-
background: rgba(251, 191, 36, 0.15);
170-
color: var(--warning-amber);
171-
}
172-
173-
.status-badge.status-partially-reimbursed {
174-
background: rgba(139, 92, 246, 0.15);
175-
color: var(--primary-purple);
176-
}
177-
178-
.status-badge.status-reimbursed {
179-
background: rgba(16, 185, 129, 0.15);
180-
color: var(--primary-green);
181-
}
182-
183-
.status-badge.status-rejected {
184-
background: rgba(239, 68, 68, 0.15);
185-
color: var(--danger-red-light);
99+
html.dark-mode .status-open,
100+
html.dark-mode .status-badge.status-open {
101+
color: var(--primary-blue-light);
186102
}
187103

104+
/* Pending/Submitted/Disputed - Warning/Amber */
105+
.status-pending,
106+
.status-submitted,
107+
.status-disputed,
108+
.status-badge.status-pending,
109+
.status-badge.status-submitted,
188110
.status-badge.status-disputed {
189-
background: rgba(245, 158, 11, 0.15);
111+
background-color: var(--bg-warning);
190112
color: var(--warning-amber);
191113
}
192114

193-
.status-badge.status-closed {
194-
background: rgba(107, 114, 128, 0.15);
195-
color: var(--neutral-gray);
196-
}
197-
198-
html.dark-mode .status-badge.status-open {
199-
background: rgba(59, 130, 246, 0.25);
200-
color: var(--primary-blue-light);
115+
html.dark-mode .status-pending,
116+
html.dark-mode .status-submitted,
117+
html.dark-mode .status-disputed,
118+
html.dark-mode .status-badge.status-pending,
119+
html.dark-mode .status-badge.status-submitted,
120+
html.dark-mode .status-badge.status-disputed {
121+
color: #fbbf24;
201122
}
202123

203-
html.dark-mode .status-badge.status-pending {
204-
background: rgba(251, 191, 36, 0.25);
205-
color: #fbbf24;
124+
/* Partially Reimbursed - Purple */
125+
.status-partially-reimbursed,
126+
.status-badge.status-partially-reimbursed {
127+
background-color: var(--bg-dcfsa);
128+
color: var(--primary-purple);
206129
}
207130

131+
html.dark-mode .status-partially-reimbursed,
208132
html.dark-mode .status-badge.status-partially-reimbursed {
209-
background: rgba(139, 92, 246, 0.25);
210133
color: var(--primary-purple-light);
211134
}
212135

136+
/* Reimbursed - Green/Success */
137+
.status-reimbursed,
138+
.status-badge.status-reimbursed {
139+
background-color: var(--bg-success);
140+
color: var(--success-green);
141+
}
142+
143+
html.dark-mode .status-reimbursed,
213144
html.dark-mode .status-badge.status-reimbursed {
214-
background: rgba(16, 185, 129, 0.25);
215145
color: var(--primary-green-light);
216146
}
217147

218-
html.dark-mode .status-badge.status-rejected {
219-
background: rgba(239, 68, 68, 0.25);
148+
/* Rejected - Red/Danger */
149+
.status-rejected,
150+
.status-badge.status-rejected {
151+
background-color: var(--bg-danger);
220152
color: var(--danger-red-light);
221153
}
222154

223-
html.dark-mode .status-badge.status-disputed {
224-
background: rgba(245, 158, 11, 0.25);
225-
color: #fbbf24;
226-
}
227-
228-
html.dark-mode .status-badge.status-closed {
229-
background: rgba(107, 114, 128, 0.25);
155+
/* Closed - Neutral/Gray */
156+
.status-closed,
157+
.status-badge.status-closed {
158+
background-color: var(--bg-neutral);
230159
color: var(--neutral-gray);
231160
}

app/assets/css/global.css

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@
6868
--gradient-fsa: linear-gradient(135deg, var(--primary-green) 0%, var(--primary-green-light) 100%);
6969
--gradient-dcfsa: linear-gradient(135deg, var(--primary-purple) 0%, var(--primary-purple-light) 100%);
7070
--gradient-warning: linear-gradient(135deg, var(--warning-amber) 0%, #f97316 100%);
71+
72+
/* Semantic Background Colors (with opacity) */
73+
--bg-hsa: rgba(59, 130, 246, 0.15);
74+
--bg-fsa: rgba(16, 185, 129, 0.15);
75+
--bg-dcfsa: rgba(139, 92, 246, 0.15);
76+
--bg-success: rgba(16, 185, 129, 0.15);
77+
--bg-warning: rgba(245, 158, 11, 0.15);
78+
--bg-danger: rgba(239, 68, 68, 0.15);
79+
--bg-neutral: rgba(107, 114, 128, 0.15);
80+
81+
/* Transitions */
82+
--transition-fast: 0.15s ease;
83+
--transition-base: 0.2s ease;
84+
--transition-slow: 0.3s ease;
7185
}
7286

7387
/* Dark Theme */
@@ -105,6 +119,15 @@ html.dark-mode {
105119
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);
106120
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
107121
--shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.4);
122+
123+
/* Semantic Background Colors (darker opacity for dark mode) */
124+
--bg-hsa: rgba(59, 130, 246, 0.25);
125+
--bg-fsa: rgba(16, 185, 129, 0.25);
126+
--bg-dcfsa: rgba(139, 92, 246, 0.25);
127+
--bg-success: rgba(16, 185, 129, 0.25);
128+
--bg-warning: rgba(245, 158, 11, 0.25);
129+
--bg-danger: rgba(239, 68, 68, 0.25);
130+
--bg-neutral: rgba(107, 114, 128, 0.25);
108131
}
109132

110133
/* ===== Reset & Base Styles ===== */

app/assets/js/components/receiptPreview.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export function closePreview() {
161161
}, 200);
162162
}
163163

164+
164165
/**
165166
* Navigate to previous/next item
166167
* @param {number} direction - -1 for previous, 1 for next

0 commit comments

Comments
 (0)