Skip to content

Commit e6f9933

Browse files
committed
feat(policyView): replace New Policy button with a FAB for selecting type
* Ingest the polcy number from the user * Display policy number in dialog header * Add icon to the dialog header
1 parent dc78b39 commit e6f9933

7 files changed

Lines changed: 110 additions & 32 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Add policy number column
2+
3+
Revision ID: 485a0ffff5b4
4+
Revises: 5aba4d45913a
5+
Create Date: 2026-01-21 23:54:44.779921
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
import sqlalchemy as sa
12+
13+
from alembic import op
14+
15+
# revision identifiers, used by Alembic.
16+
revision: str = "485a0ffff5b4"
17+
down_revision: Union[str, Sequence[str], None] = "5aba4d45913a"
18+
branch_labels: Union[str, Sequence[str], None] = None
19+
depends_on: Union[str, Sequence[str], None] = None
20+
21+
22+
def upgrade() -> None:
23+
"""Upgrade schema."""
24+
# ### commands auto generated by Alembic - please adjust! ###
25+
with op.batch_alter_table("policies", schema=None) as batch_op:
26+
batch_op.add_column(sa.Column("policy_number", sa.String(), nullable=True))
27+
28+
# ### end Alembic commands ###
29+
30+
31+
def downgrade() -> None:
32+
"""Downgrade schema."""
33+
# ### commands auto generated by Alembic - please adjust! ###
34+
with op.batch_alter_table("policies", schema=None) as batch_op:
35+
batch_op.drop_column("policy_number")
36+
37+
# ### end Alembic commands ###

backend/app/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def create_policy(
139139
household_id: int = Form(...),
140140
asset_id: Optional[int] = Form(None),
141141
provider: str = Form(...),
142+
policy_number: str = Form(...),
142143
type: str = Form(...),
143144
start_date: date = Form(...),
144145
end_date: date = Form(None),
@@ -158,6 +159,7 @@ def create_policy(
158159
household_id=household_id,
159160
asset_id=asset_id,
160161
provider=provider,
162+
policy_number=policy_number,
161163
type=type,
162164
start_date=start_date,
163165
end_date=end_date,
@@ -216,6 +218,7 @@ def update_policy(
216218
household_id: int = Form(...),
217219
asset_id: Optional[int] = Form(None),
218220
provider: str = Form(...),
221+
policy_number: str = Form(...),
219222
type: str = Form(...),
220223
start_date: date = Form(...),
221224
end_date: date = Form(...),
@@ -239,6 +242,7 @@ def update_policy(
239242
policy.household_id = household_id
240243
policy.asset_id = asset_id
241244
policy.provider = provider
245+
policy.policy_number = policy_number
242246
policy.type = type
243247
policy.start_date = start_date
244248
policy.end_date = end_date

backend/app/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ class Policy(Base):
3333
household_id = Column(Integer, ForeignKey("households.id"), nullable=False)
3434
asset_id = Column(Integer, ForeignKey("assets.id"), nullable=True)
3535
provider = Column(String, index=True, nullable=False)
36+
policy_number = Column(String, nullable=True)
3637
type = Column(String, nullable=False)
3738
start_date = Column(Date, nullable=False)
38-
end_date = Column(Date, nullable=False)
39+
end_date = Column(Date, nullable=True)
3940
premium = Column(Float, nullable=False)
4041
attributes = Column(JSON, nullable=False, default={})
4142
document_path = Column(String, nullable=True)

frontend/src/components/PolicyDetailsDialog.vue

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@
77
>
88
<v-card rounded="lg">
99
<v-toolbar :color="getHeaderColour(policy.type)">
10+
<template v-slot:prepend>
11+
<div class="ml-4">
12+
<v-icon :icon="getHeaderIcon(policy.type)" />
13+
</div>
14+
</template>
1015
<v-toolbar-title class="font-weight-bold text-white">
1116
{{ policy.provider }}
12-
<span class="text-subtitle-2 ml-2 opacity-80 text-white"> {{ policy.type }} Policy </span>
17+
<span v-if="policy.policy_number" class="text-subtitle-2 ml-2 opacity-80 text-white">
18+
Policy No. {{ policy.policy_number }}
19+
</span>
1320
</v-toolbar-title>
1421
<v-spacer />
1522
<v-btn icon="mdi-close" @click="$emit('update:modelValue', false)" />
@@ -170,7 +177,7 @@
170177
<script>
171178
import { getFileUrl } from '@/services/api'
172179
import { currencyFormat } from '@/utils/Formats'
173-
import { getPolicyColour } from '@/utils/PolicyStyles'
180+
import { getPolicyColour, getPolicyIcon } from '@/utils/PolicyStyles'
174181
175182
import BuildingsPolicyDetails from '@/components/details/BuildingsPolicyDetails.vue'
176183
import CarPolicyDetails from '@/components/details/CarPolicyDetails.vue'
@@ -213,6 +220,9 @@ export default {
213220
getHeaderColour(policyType) {
214221
return getPolicyColour(policyType)
215222
},
223+
getHeaderIcon(policyType) {
224+
return getPolicyIcon(policyType)
225+
},
216226
getRenewalColor(dateStr) {
217227
if (!dateStr) return 'text-grey'
218228
const daysLeft = (new Date(dateStr) - new Date()) / (1000 * 60 * 60 * 24)

frontend/src/components/PolicyForm.vue

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@
2222
/>
2323
</v-col>
2424
<v-col cols="12" sm="6">
25-
<v-select
26-
v-model="form.type"
27-
:items="policyTypes"
28-
label="Type"
25+
<v-text-field
26+
v-model="form.policy_number"
27+
label="Policy No."
2928
variant="outlined"
3029
density="comfortable"
3130
/>
@@ -135,9 +134,9 @@
135134
</v-form>
136135
</v-card-text>
137136

138-
<v-divider></v-divider>
137+
<v-divider />
139138
<v-card-actions class="pa-4">
140-
<v-spacer></v-spacer>
139+
<v-spacer />
141140
<v-btn variant="text" @click="$emit('update:modelValue', false)">Cancel</v-btn>
142141
<v-btn color="primary" variant="flat" @click="submit" :loading="loading">Save Policy</v-btn>
143142
</v-card-actions>
@@ -164,27 +163,28 @@ export default {
164163
PetPolicyForm,
165164
},
166165
props: {
167-
modelValue: Boolean,
168-
loading: Boolean,
169166
assets: Array,
170-
policyToEdit: Object,
171167
currencyCode: String,
168+
loading: Boolean,
169+
modelValue: Boolean,
170+
policyToEdit: Object,
171+
policyType: String,
172172
},
173173
emits: ['update:modelValue', 'submit'],
174174
data() {
175175
return {
176176
form: {
177177
asset_id: null,
178+
type: this.policyType,
178179
provider: '',
179-
type: null,
180+
policy_number: '',
180181
start_date: '',
181182
end_date: null,
182183
premium: '',
183184
frequency: 'Annual',
184185
attributes: {},
185186
},
186187
file: null,
187-
policyTypes: ['Buildings', 'Car', 'Contents', 'Life', 'Medical', 'Pet'],
188188
}
189189
},
190190
computed: {
@@ -202,8 +202,9 @@ export default {
202202
} else {
203203
this.form = {
204204
asset_id: null,
205+
type: this.policyType,
205206
provider: '',
206-
type: null,
207+
policy_number: '',
207208
start_date: '',
208209
end_date: '',
209210
premium: '',

frontend/src/utils/PolicyStyles.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,32 @@ export const POLICY_THEME = {
22
Buildings: {
33
colour: 'blue-grey-darken-2',
44
icon: 'mdi-home-city',
5-
label: 'Buildings Insurance',
5+
label: 'Buildings',
66
},
77
Car: {
88
colour: 'blue-darken-2',
99
icon: 'mdi-car',
10-
label: 'Vehicle Insurance',
10+
label: 'Car',
1111
},
1212
Contents: {
1313
colour: 'amber-darken-3',
1414
icon: 'mdi-sofa',
15-
label: 'Contents Insurance',
15+
label: 'Contents',
1616
},
1717
Life: {
1818
colour: 'purple-darken-2',
1919
icon: 'mdi-heart-pulse',
20-
label: 'Life Insurance',
20+
label: 'Life',
2121
},
2222
Medical: {
2323
colour: 'teal-darken-2',
2424
icon: 'mdi-medical-bag',
25-
label: 'Health Insurance',
25+
label: 'Medical',
2626
},
2727
Pet: {
2828
colour: 'brown-darken-1',
2929
icon: 'mdi-paw',
30-
label: 'Pet Insurance',
31-
},
32-
Other: {
33-
colour: 'grey-darken-2',
34-
icon: 'mdi-file-certificate',
35-
label: 'Other Policy',
30+
label: 'Pet',
3631
},
3732
}
3833

frontend/src/views/PoliciesView.vue

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,31 @@
44
<v-col>
55
<h1 class="text-h4 font-weight-thin">Policies</h1>
66
</v-col>
7-
<v-col cols="auto">
8-
<v-btn color="primary" prepend-icon="mdi-plus" size="large" @click="policyDialog = true">
9-
Add Policy
10-
</v-btn>
11-
</v-col>
127
</v-row>
138

9+
<v-fab app="true" color="primary" location="right bottom" size="large" icon>
10+
<v-icon :icon="openFab ? 'mdi-close' : 'mdi-plus'" />
11+
<v-speed-dial
12+
v-model="openFab"
13+
location="top left"
14+
transition="slide-y-reverse-transition"
15+
activator="parent"
16+
>
17+
<v-btn
18+
v-for="(config, type) in createOptions"
19+
:key="type"
20+
:color="config.colour"
21+
:prepend-icon="config.icon"
22+
density="default"
23+
rounded="xl"
24+
size="large"
25+
@click="openPolicyDialog(type)"
26+
>
27+
{{ config.label }}
28+
</v-btn>
29+
</v-speed-dial>
30+
</v-fab>
31+
1432
<div class="mb-6">
1533
<div class="d-flex align-center mb-2">
1634
<v-icon color="success" icon="mdi-shield-check" class="mr-2" />
@@ -51,13 +69,15 @@
5169
:currency-code="currencyCode"
5270
:loading="submitting"
5371
:policy-to-edit="selectedPolicy"
72+
:policy-type="policyDialogType"
5473
@submit="handlePolicySubmit"
5574
/>
5675
</div>
5776
</template>
5877

5978
<script>
6079
import api from '@/services/api'
80+
import { POLICY_THEME } from '@/utils/PolicyStyles'
6181
import PolicyList from '@/components/PolicyList.vue'
6282
import PolicyForm from '@/components/PolicyForm.vue'
6383
@@ -74,8 +94,11 @@ export default {
7494
assets: [],
7595
loading: false,
7696
policyDialog: false,
97+
policyDialogType: null,
7798
submitting: false,
7899
selectedPolicy: null,
100+
openFab: false,
101+
policyTheme: POLICY_THEME,
79102
}
80103
},
81104
watch: {
@@ -102,7 +125,9 @@ export default {
102125
return new Date(p.end_date) >= today
103126
})
104127
},
105-
128+
createOptions() {
129+
return this.policyTheme
130+
},
106131
expiredPolicies() {
107132
const today = new Date()
108133
today.setHours(0, 0, 0, 0)
@@ -114,6 +139,10 @@ export default {
114139
},
115140
},
116141
methods: {
142+
openPolicyDialog(type) {
143+
this.policyDialogType = type
144+
this.policyDialog = true
145+
},
117146
openEditDialog(policy) {
118147
this.selectedPolicy = policy
119148
this.policyDialog = true
@@ -139,6 +168,7 @@ export default {
139168
let formData = new FormData()
140169
formData.append('household_id', this.currentHousehold.id)
141170
formData.append('provider', payload.provider)
171+
formData.append('policy_number', payload.policy_number)
142172
formData.append('type', payload.type)
143173
formData.append('start_date', payload.start_date)
144174
formData.append('end_date', payload.end_date)

0 commit comments

Comments
 (0)