feat: customizable portal gradient theme + LTC repair form fixes
- Add portal gradient branding settings with 4 presets (Green/Teal, Blue/Purple, Sunset Orange, Dark Slate) and custom color picker - Live preview in settings, onchange updates colors reactively - Dynamic gradient applied across portal home, CSS, and card elements - Fix after photos visibility (conditional on resolved=yes) - Fix technician section gating on portal repair form - Move Create Sale Order button to form header for visibility - Fix portal home row width inconsistency (xpath target change) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,6 +38,14 @@ class AuthorizerPortal(CustomerPortal):
|
|||||||
response.qcontext['sign_count'] = sign_count
|
response.qcontext['sign_count'] = sign_count
|
||||||
response.qcontext['sign_module_available'] = sign_module_available
|
response.qcontext['sign_module_available'] = sign_module_available
|
||||||
|
|
||||||
|
ICP = request.env['ir.config_parameter'].sudo()
|
||||||
|
g_start = ICP.get_param('fusion_claims.portal_gradient_start', '#5ba848')
|
||||||
|
g_mid = ICP.get_param('fusion_claims.portal_gradient_mid', '#3a8fb7')
|
||||||
|
g_end = ICP.get_param('fusion_claims.portal_gradient_end', '#2e7aad')
|
||||||
|
response.qcontext['portal_gradient'] = (
|
||||||
|
'linear-gradient(135deg, %s 0%%, %s 60%%, %s 100%%)' % (g_start, g_mid, g_end)
|
||||||
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _prepare_home_portal_values(self, counters):
|
def _prepare_home_portal_values(self, counters):
|
||||||
|
|||||||
@@ -339,7 +339,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.assessment-express-form .card-header.bg-primary {
|
.assessment-express-form .card-header.bg-primary {
|
||||||
background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%) !important;
|
background: var(--fc-portal-gradient, linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%)) !important;
|
||||||
border-radius: 12px 12px 0 0;
|
border-radius: 12px 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +391,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.assessment-express-form .progress-bar {
|
.assessment-express-form .progress-bar {
|
||||||
background: linear-gradient(90deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);
|
background: var(--fc-portal-gradient, linear-gradient(90deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Section Separators */
|
/* Section Separators */
|
||||||
@@ -415,7 +415,7 @@
|
|||||||
|
|
||||||
/* New Assessment Card on Portal Home */
|
/* New Assessment Card on Portal Home */
|
||||||
.portal-new-assessment-card {
|
.portal-new-assessment-card {
|
||||||
background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%) !important;
|
background: var(--fc-portal-gradient, linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%)) !important;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +450,7 @@
|
|||||||
|
|
||||||
/* Authorizer Portal Card on Portal Home */
|
/* Authorizer Portal Card on Portal Home */
|
||||||
.portal-authorizer-card {
|
.portal-authorizer-card {
|
||||||
background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%) !important;
|
background: var(--fc-portal-gradient, linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%)) !important;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +522,7 @@
|
|||||||
|
|
||||||
/* Welcome Header */
|
/* Welcome Header */
|
||||||
.auth-dash-header {
|
.auth-dash-header {
|
||||||
background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);
|
background: var(--fc-portal-gradient, linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%));
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -178,8 +178,9 @@
|
|||||||
for="resolved_no">No</label>
|
for="resolved_no">No</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3" id="resolution_section"
|
<div id="resolution_section"
|
||||||
style="display: none;">
|
style="display: none;">
|
||||||
|
<div class="mb-3">
|
||||||
<label for="resolution_description"
|
<label for="resolution_description"
|
||||||
class="form-label">
|
class="form-label">
|
||||||
Describe the Solution
|
Describe the Solution
|
||||||
@@ -197,10 +198,11 @@
|
|||||||
class="form-control" multiple="multiple"
|
class="form-control" multiple="multiple"
|
||||||
accept="image/*"/>
|
accept="image/*"/>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
Optional. Attach after repair is completed. Up to 4 photos (max 10MB each).
|
Attach after repair is completed. Up to 4 photos (max 10MB each).
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
<div class="text-center mt-4">
|
<div class="text-center mt-4">
|
||||||
|
|||||||
@@ -4,13 +4,17 @@
|
|||||||
<!-- ==================== PORTAL HOME EXTENSION ==================== -->
|
<!-- ==================== PORTAL HOME EXTENSION ==================== -->
|
||||||
|
|
||||||
<template id="portal_my_home_authorizer" inherit_id="portal.portal_my_home" priority="40">
|
<template id="portal_my_home_authorizer" inherit_id="portal.portal_my_home" priority="40">
|
||||||
<!-- Insert Fusion content at the very top, before alert category -->
|
<!-- Insert Fusion content before the default portal docs grid -->
|
||||||
<xpath expr="//div[@id='portal_alert_category']" position="before">
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="before">
|
||||||
<t t-if="request.env.user.partner_id.is_authorizer or request.env.user.partner_id.is_sales_rep_portal or request.env.user.partner_id.is_client_portal or request.env.user.partner_id.is_technician_portal">
|
<t t-if="request.env.user.partner_id.is_authorizer or request.env.user.partner_id.is_sales_rep_portal or request.env.user.partner_id.is_client_portal or request.env.user.partner_id.is_technician_portal">
|
||||||
|
<t t-set="fc_gradient" t-value="portal_gradient or 'linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%)'"/>
|
||||||
|
<style>
|
||||||
|
:root { --fc-portal-gradient: <t t-out="fc_gradient"/>; }
|
||||||
|
</style>
|
||||||
<!-- Welcome Banner -->
|
<!-- Welcome Banner -->
|
||||||
<div class="row mb-4">
|
<div class="row g-3 mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="border-0 shadow-sm p-4" style="background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%); border-radius: 12px;">
|
<div class="border-0 shadow-sm p-4" t-attf-style="background: {{fc_gradient}}; border-radius: 12px;">
|
||||||
<div class="d-flex align-items-center text-white">
|
<div class="d-flex align-items-center text-white">
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<h4 class="mb-1" style="color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.1);">
|
<h4 class="mb-1" style="color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.1);">
|
||||||
@@ -71,7 +75,7 @@
|
|||||||
<a href="/my/accessibility" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
<a href="/my/accessibility" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-wheelchair fa-lg text-white"/>
|
<i class="fa fa-wheelchair fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,7 +94,7 @@
|
|||||||
<a href="/my/sales" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
<a href="/my/sales" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-briefcase fa-lg text-white"/>
|
<i class="fa fa-briefcase fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,7 +113,7 @@
|
|||||||
<a href="/my/assessments" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
<a href="/my/assessments" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-clipboard fa-lg text-white"/>
|
<i class="fa fa-clipboard fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -131,7 +135,7 @@
|
|||||||
</t>
|
</t>
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-pencil-square-o fa-lg text-white"/>
|
<i class="fa fa-pencil-square-o fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -172,7 +176,7 @@
|
|||||||
<a href="/my/technician" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
<a href="/my/technician" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-truck fa-lg text-white"/>
|
<i class="fa fa-truck fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -191,7 +195,7 @@
|
|||||||
<a href="/my/funding-claims" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
<a href="/my/funding-claims" class="card h-100 border-0 shadow-sm text-decoration-none" style="border-radius: 12px; min-height: 100px;">
|
||||||
<div class="card-body d-flex align-items-center p-4">
|
<div class="card-body d-flex align-items-center p-4">
|
||||||
<div class="me-3">
|
<div class="me-3">
|
||||||
<div class="rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-circle d-flex align-items-center justify-content-center" t-attf-style="width: 50px; height: 50px; background: {{fc_gradient}};">
|
||||||
<i class="fa fa-file-text-o fa-lg text-white"/>
|
<i class="fa fa-file-text-o fa-lg text-white"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,16 +210,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ADP Posting Schedule Card -->
|
<!-- ADP Posting Schedule Card -->
|
||||||
<div class="row mb-4" t-if="next_posting_date">
|
<div class="row g-3 mb-4" t-if="next_posting_date">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0 overflow-hidden" style="border-radius: 12px;">
|
<div class="card shadow-sm border-0 overflow-hidden" style="border-radius: 12px;">
|
||||||
<div class="card-header py-3" style="background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="card-header py-3" t-attf-style="background: {{fc_gradient}};">
|
||||||
<h5 class="mb-0 text-white"><i class="fa fa-calendar me-2"/>Upcoming ADP Posting Schedule</h5>
|
<h5 class="mb-0 text-white"><i class="fa fa-calendar me-2"/>Upcoming ADP Posting Schedule</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body" style="background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);">
|
<div class="card-body" style="background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col-md-4 text-center mb-3 mb-md-0">
|
<div class="col-md-4 text-center mb-3 mb-md-0">
|
||||||
<div class="rounded-3 p-4" style="background: linear-gradient(135deg, #5ba848 0%, #3a8fb7 60%, #2e7aad 100%);">
|
<div class="rounded-3 p-4" t-attf-style="background: {{fc_gradient}};">
|
||||||
<small class="d-block" style="color: rgba(255,255,255,0.8);">Next ADP Posting</small>
|
<small class="d-block" style="color: rgba(255,255,255,0.8);">Next ADP Posting</small>
|
||||||
<h2 class="mb-1 text-white"><t t-out="next_posting_display"/></h2>
|
<h2 class="mb-1 text-white"><t t-out="next_posting_display"/></h2>
|
||||||
<small style="color: rgba(255,255,255,0.8);"><t t-out="next_posting_weekday"/></small>
|
<small style="color: rgba(255,255,255,0.8);"><t t-out="next_posting_weekday"/></small>
|
||||||
|
|||||||
@@ -487,6 +487,80 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
help='Minimum 4 characters. Share with facility staff to access the repair form.',
|
help='Minimum 4 characters. Share with facility staff to access the repair form.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# PORTAL BRANDING
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
fc_portal_gradient_preset = fields.Selection([
|
||||||
|
('green_teal', 'Green to Teal (Default)'),
|
||||||
|
('blue_purple', 'Blue to Purple'),
|
||||||
|
('orange_red', 'Sunset Orange'),
|
||||||
|
('dark_slate', 'Dark Slate'),
|
||||||
|
('custom', 'Custom'),
|
||||||
|
],
|
||||||
|
string='Portal Gradient Theme',
|
||||||
|
config_parameter='fusion_claims.portal_gradient_preset',
|
||||||
|
default='green_teal',
|
||||||
|
)
|
||||||
|
fc_portal_gradient_start = fields.Char(
|
||||||
|
string='Gradient Start Color',
|
||||||
|
config_parameter='fusion_claims.portal_gradient_start',
|
||||||
|
default='#5ba848',
|
||||||
|
)
|
||||||
|
fc_portal_gradient_mid = fields.Char(
|
||||||
|
string='Gradient Mid Color',
|
||||||
|
config_parameter='fusion_claims.portal_gradient_mid',
|
||||||
|
default='#3a8fb7',
|
||||||
|
)
|
||||||
|
fc_portal_gradient_end = fields.Char(
|
||||||
|
string='Gradient End Color',
|
||||||
|
config_parameter='fusion_claims.portal_gradient_end',
|
||||||
|
default='#2e7aad',
|
||||||
|
)
|
||||||
|
fc_portal_gradient_preview = fields.Html(
|
||||||
|
string='Gradient Preview',
|
||||||
|
compute='_compute_portal_gradient_preview',
|
||||||
|
sanitize=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.onchange('fc_portal_gradient_preset')
|
||||||
|
def _onchange_portal_gradient_preset(self):
|
||||||
|
preset = self.fc_portal_gradient_preset
|
||||||
|
if preset and preset != 'custom' and preset in self.GRADIENT_PRESETS:
|
||||||
|
start, mid, end = self.GRADIENT_PRESETS[preset]
|
||||||
|
self.fc_portal_gradient_start = start
|
||||||
|
self.fc_portal_gradient_mid = mid
|
||||||
|
self.fc_portal_gradient_end = end
|
||||||
|
|
||||||
|
@api.depends(
|
||||||
|
'fc_portal_gradient_preset',
|
||||||
|
'fc_portal_gradient_start',
|
||||||
|
'fc_portal_gradient_mid',
|
||||||
|
'fc_portal_gradient_end',
|
||||||
|
)
|
||||||
|
def _compute_portal_gradient_preview(self):
|
||||||
|
for rec in self:
|
||||||
|
start = rec.fc_portal_gradient_start or '#5ba848'
|
||||||
|
mid = rec.fc_portal_gradient_mid or '#3a8fb7'
|
||||||
|
end = rec.fc_portal_gradient_end or '#2e7aad'
|
||||||
|
gradient = 'linear-gradient(135deg, %s 0%%, %s 60%%, %s 100%%)' % (start, mid, end)
|
||||||
|
rec.fc_portal_gradient_preview = (
|
||||||
|
'<div style="background: %s; border-radius: 12px; padding: 24px; min-height: 80px;">'
|
||||||
|
'<div style="display: flex; align-items: center; color: #fff;">'
|
||||||
|
'<div style="flex: 1;">'
|
||||||
|
'<h5 style="color: #fff; margin-bottom: 4px;">'
|
||||||
|
'<i class="fa fa-hand-peace-o" style="margin-right: 8px;"></i>'
|
||||||
|
'Welcome back, Preview User!</h5>'
|
||||||
|
'<small style="color: rgba(255,255,255,0.9);">'
|
||||||
|
'This is how your portal dashboard header will look.</small>'
|
||||||
|
'</div>'
|
||||||
|
'<div style="text-align: right;">'
|
||||||
|
'<div style="background: rgba(255,255,255,0.2); border-radius: 8px; padding: 8px 12px;">'
|
||||||
|
'<small style="display: block; color: rgba(255,255,255,0.8);">Preview</small>'
|
||||||
|
'<strong style="color: #fff;">Live</strong>'
|
||||||
|
'</div></div></div></div>'
|
||||||
|
) % gradient
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def get_values(self):
|
def get_values(self):
|
||||||
res = super().get_values()
|
res = super().get_values()
|
||||||
@@ -603,6 +677,14 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
elif not ICP.get_param('fusion_claims.odsp_default_office_id', ''):
|
elif not ICP.get_param('fusion_claims.odsp_default_office_id', ''):
|
||||||
ICP.set_param('fusion_claims.odsp_default_office_id', '')
|
ICP.set_param('fusion_claims.odsp_default_office_id', '')
|
||||||
|
|
||||||
|
# Apply gradient preset colors to ICP so the portal reads them
|
||||||
|
preset = self.fc_portal_gradient_preset
|
||||||
|
if preset and preset != 'custom' and preset in self.GRADIENT_PRESETS:
|
||||||
|
start, mid, end = self.GRADIENT_PRESETS[preset]
|
||||||
|
ICP.set_param('fusion_claims.portal_gradient_start', start)
|
||||||
|
ICP.set_param('fusion_claims.portal_gradient_mid', mid)
|
||||||
|
ICP.set_param('fusion_claims.portal_gradient_end', end)
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# ACTION METHODS
|
# ACTION METHODS
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
@@ -618,3 +700,31 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
'context': {},
|
'context': {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -- Portal Gradient Presets -----------------------------------------------
|
||||||
|
|
||||||
|
GRADIENT_PRESETS = {
|
||||||
|
'green_teal': ('#5ba848', '#3a8fb7', '#2e7aad'),
|
||||||
|
'blue_purple': ('#4a90d9', '#7b68ee', '#6a5acd'),
|
||||||
|
'orange_red': ('#f7971e', '#e44d26', '#c0392b'),
|
||||||
|
'dark_slate': ('#2c3e50', '#4a6274', '#34495e'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _apply_gradient_preset(self, preset_key):
|
||||||
|
start, mid, end = self.GRADIENT_PRESETS[preset_key]
|
||||||
|
self.fc_portal_gradient_preset = preset_key
|
||||||
|
self.fc_portal_gradient_start = start
|
||||||
|
self.fc_portal_gradient_mid = mid
|
||||||
|
self.fc_portal_gradient_end = end
|
||||||
|
|
||||||
|
def action_set_gradient_green_teal(self):
|
||||||
|
self._apply_gradient_preset('green_teal')
|
||||||
|
|
||||||
|
def action_set_gradient_blue_purple(self):
|
||||||
|
self._apply_gradient_preset('blue_purple')
|
||||||
|
|
||||||
|
def action_set_gradient_orange_red(self):
|
||||||
|
self._apply_gradient_preset('orange_red')
|
||||||
|
|
||||||
|
def action_set_gradient_dark_slate(self):
|
||||||
|
self._apply_gradient_preset('dark_slate')
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Repair Request">
|
<form string="Repair Request">
|
||||||
<header>
|
<header>
|
||||||
|
<button name="action_create_sale_order" type="object"
|
||||||
|
string="Create Sale Order" class="btn-primary"
|
||||||
|
invisible="sale_order_id"/>
|
||||||
<field name="stage_id" widget="statusbar"
|
<field name="stage_id" widget="statusbar"
|
||||||
options="{'clickable': '1'}"/>
|
options="{'clickable': '1'}"/>
|
||||||
</header>
|
</header>
|
||||||
@@ -98,9 +101,6 @@
|
|||||||
<field name="repair_value"/>
|
<field name="repair_value"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<button name="action_create_sale_order" type="object"
|
|
||||||
string="Create Sale Order" class="btn-primary"
|
|
||||||
invisible="sale_order_id"/>
|
|
||||||
</page>
|
</page>
|
||||||
|
|
||||||
<page string="Photos & Notes" name="photos">
|
<page string="Photos & Notes" name="photos">
|
||||||
|
|||||||
@@ -519,6 +519,67 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== PORTAL BRANDING ===== -->
|
||||||
|
<h2>Portal Branding</h2>
|
||||||
|
<div class="row mt16 o_settings_container">
|
||||||
|
<div class="col-12 o_setting_box">
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<span class="o_form_label">Portal Gradient Theme</span>
|
||||||
|
<div class="text-muted mb-3">
|
||||||
|
Choose a preset gradient or customize your own colors for the portal dashboard.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<field name="fc_portal_gradient_preset" widget="radio"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex flex-wrap gap-2 mb-3">
|
||||||
|
<button type="object" name="action_set_gradient_green_teal"
|
||||||
|
class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-2">
|
||||||
|
<span style="display:inline-block;width:20px;height:20px;border-radius:4px;background:linear-gradient(135deg,#5ba848 0%,#3a8fb7 60%,#2e7aad 100%);"/>
|
||||||
|
Green to Teal
|
||||||
|
</button>
|
||||||
|
<button type="object" name="action_set_gradient_blue_purple"
|
||||||
|
class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-2">
|
||||||
|
<span style="display:inline-block;width:20px;height:20px;border-radius:4px;background:linear-gradient(135deg,#4a90d9 0%,#7b68ee 60%,#6a5acd 100%);"/>
|
||||||
|
Blue to Purple
|
||||||
|
</button>
|
||||||
|
<button type="object" name="action_set_gradient_orange_red"
|
||||||
|
class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-2">
|
||||||
|
<span style="display:inline-block;width:20px;height:20px;border-radius:4px;background:linear-gradient(135deg,#f7971e 0%,#e44d26 60%,#c0392b 100%);"/>
|
||||||
|
Sunset Orange
|
||||||
|
</button>
|
||||||
|
<button type="object" name="action_set_gradient_dark_slate"
|
||||||
|
class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-2">
|
||||||
|
<span style="display:inline-block;width:20px;height:20px;border-radius:4px;background:linear-gradient(135deg,#2c3e50 0%,#4a6274 60%,#34495e 100%);"/>
|
||||||
|
Dark Slate
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3" invisible="fc_portal_gradient_preset != 'custom'">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<span class="o_form_label">Start Color</span>
|
||||||
|
<field name="fc_portal_gradient_start" widget="color"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<span class="o_form_label">Mid Color</span>
|
||||||
|
<field name="fc_portal_gradient_mid" widget="color"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<span class="o_form_label">End Color</span>
|
||||||
|
<field name="fc_portal_gradient_end" widget="color"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="o_form_label">Preview</span>
|
||||||
|
<div class="text-muted small">Preview updates after saving settings.</div>
|
||||||
|
</div>
|
||||||
|
<field name="fc_portal_gradient_preview" widget="html" readonly="1" class="border-0"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Hidden fields for field mappings (still needed for ir.config_parameter storage) -->
|
<!-- Hidden fields for field mappings (still needed for ir.config_parameter storage) -->
|
||||||
<div class="d-none">
|
<div class="d-none">
|
||||||
<field name="fc_field_sale_type"/>
|
<field name="fc_field_sale_type"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user