Add platform SMTP and firm wizard invite email

This commit is contained in:
A R R R Associates
2026-07-02 23:43:24 +05:30
parent b4b8dc97fd
commit b84090d8c9
12 changed files with 821 additions and 45 deletions
+1 -2
View File
@@ -1,4 +1,4 @@
from fastapi import FastAPI
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from app.modules.clients.ui import router as clients_ui_router, portal_router as client_portal_router
@@ -56,4 +56,3 @@ def mount_ui(app: FastAPI) -> None:
app.include_router(engagements_ui_router)
app.include_router(client_portal_router)
app.include_router(consultant_portal_router)
+17 -31
View File
@@ -1,4 +1,4 @@
<!doctype html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
@@ -108,7 +108,7 @@
{% if firm_branding.logo_url %}<img src="{{ firm_branding.logo_url }}" alt="{{ current_firm_name }} logo" class="h-11 w-11 rounded-2xl bg-white object-contain p-1 shadow-soft" />{% else %}<div class="flex h-11 w-11 items-center justify-center rounded-2xl bg-brand-500 font-bold text-white shadow-soft">{{ (current_firm_name[:2] if current_firm_name else 'AF')|upper }}</div>{% endif %}
<div class="min-w-0">
<div class="truncate text-sm font-semibold tracking-wide">{{ current_firm_name }}</div>
<div class="truncate text-xs text-slate-400">{% if full_auth %}{{ current_branch_name }}{% if current_branch_name and current_branch_name != "-" %} Branch{% endif %} | Workspace{% elif domain_context.is_resolved %}{{ current_branch_name or 'Domain Workspace' }}{% else %}Secure Practice Workspace{% endif %}</div>
<div class="truncate text-xs text-slate-400">{% if full_auth %}{{ current_branch_name }}{% if current_branch_name and current_branch_name != "-" %} Branch{% endif %} Workspace{% elif domain_context.is_resolved %}{{ current_branch_name or 'Domain Workspace' }}{% else %}Secure Practice Workspace{% endif %}</div>
</div>
</div>
@@ -153,7 +153,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/employee') or current_path.startswith('/alerts') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>My Workspace</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
{% if can_view_employee_portal(current_user, ui_perms, ui_roles) %}
@@ -186,7 +186,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/partner') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Partner Workspace</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
<a href="/partner/dashboard" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path == '/partner/dashboard' %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">Overview</a>
@@ -201,7 +201,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/manager') or current_path.startswith('/employees/work') or current_path.startswith('/employees/progress') or current_path.startswith('/employees/attendance') or current_path.startswith('/employees/leave') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Team Workspace</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
{% if can_manage_employee_work(current_user, ui_perms, ui_roles) %}
@@ -226,7 +226,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/billing') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Billing</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
<a href="/billing" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path == '/billing' %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">Invoices</a>
@@ -244,7 +244,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/employees') and not (current_path.startswith('/employees/work') or current_path.startswith('/employees/progress') or current_path.startswith('/employees/attendance') or current_path == '/employees/leave') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Team Administration</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
{% if can_view_employee_dashboard(current_user, ui_perms, ui_roles) %}<a href="/employees/dashboard" class="block rounded-lg px-3 py-1.5 text-sm text-slate-300 transition hover:bg-slate-800 hover:text-white">HR Dashboard</a>{% endif %}
@@ -282,7 +282,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/system-settings/users') or current_path.startswith('/system-settings/rbac') or current_path.startswith('/services') or current_path.startswith('/clients') or current_path.startswith('/consultants') or current_path.startswith('/email') or current_path.startswith('/notice-cases') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Firm Administration</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
{% if "Firm Admin" in ui_roles or is_system_admin_user %}
@@ -338,7 +338,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/domains') or current_path.startswith('/platform-billing') or current_path.startswith('/marketplace') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Platform</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
<div class="pt-3 text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-500">Domain Configuration</div>
@@ -348,11 +348,11 @@
<a href="/domains/consultant-domains" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path.startswith('/domains/consultant-domains') %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">Consultant Domains</a>
<a href="/domains/verification" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path.startswith('/domains/verification') %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">DNS Verification</a>
<a href="/domains/ssl" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path.startswith('/domains/ssl') %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">SSL Status</a>
{% if can_view_platform_billing(current_user, ui_perms, ui_roles) or can_view_marketplace_leads(current_user, ui_perms, ui_roles) %}
<div class="pt-3 text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-500">Platform Operations</div>
<a href="/email/platform-smtp" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path.startswith('/email/platform-smtp') %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">Platform SMTP</a>
<a href="/wizards/system/firm/new" class="block rounded-lg px-3 py-1.5 text-sm transition {% if current_path.startswith('/wizards/system/firm') %}bg-brand-600 text-white{% else %}text-slate-300 hover:bg-slate-800 hover:text-white{% endif %}">Create Firm Wizard</a>
{% if can_view_platform_billing(current_user, ui_perms, ui_roles) %}<a href="/platform-billing" class="block rounded-lg px-3 py-1.5 text-sm text-slate-300 transition hover:bg-slate-800 hover:text-white">Platform Billing</a>{% endif %}
{% if can_view_marketplace_leads(current_user, ui_perms, ui_roles) %}<a href="/marketplace" class="block rounded-lg px-3 py-1.5 text-sm text-slate-300 transition hover:bg-slate-800 hover:text-white">Marketplace</a>{% endif %}
{% endif %}
</div>
</details>
{% endif %}
@@ -360,7 +360,7 @@
<details class="group rounded-xl" {% if current_path.startswith('/system-settings') %}open{% endif %}>
<summary class="flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2 text-sm font-semibold transition hover:bg-slate-800">
<span>Core Setup</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90">&gt;</span>
<span class="text-xs text-slate-400 transition group-open:rotate-90"></span>
</summary>
<div class="mt-1 space-y-1 border-l border-slate-700/70 pl-3">
{% if can_view_settings(current_user, ui_perms, ui_roles) %}
@@ -400,11 +400,11 @@
<div class="font-medium text-slate-800">{{ current_user.full_name or current_user.email }}</div>
<div class="text-slate-500">{{ current_user.email }}</div>
{% if current_user.qualification or current_user.designation %}
<div class="text-xs text-slate-500">{{ current_user.qualification or '' }}{% if current_user.qualification and current_user.designation %} | {% endif %}{{ current_user.designation or '' }}</div>
<div class="text-xs text-slate-500">{{ current_user.qualification or '' }}{% if current_user.qualification and current_user.designation %} {% endif %}{{ current_user.designation or '' }}</div>
{% endif %}
<div class="text-xs text-slate-400">
Your Firm: {{ current_firm_name }}
&gt; Branch: {{ current_branch_name }}{% if active_financial_year %} &gt; FY: {{ active_financial_year }}{% endif %}
Branch: {{ current_branch_name }}{% if active_financial_year %} FY: {{ active_financial_year }}{% endif %}
</div>
<div class="mt-2 flex justify-end gap-2">
{% if "Consultant" in ui_roles %}
@@ -426,7 +426,7 @@
</div>
{% else %}
{% if domain_context.is_resolved %}
<div class="mb-2 text-xs text-slate-500">{{ current_firm_name }}{% if current_branch_name %} | {{ current_branch_name }}{% endif %}</div>
<div class="mb-2 text-xs text-slate-500">{{ current_firm_name }}{% if current_branch_name %} {{ current_branch_name }}{% endif %}</div>
{% endif %}
<a class="inline-flex rounded-lg bg-brand-600 px-3 py-2 text-sm font-medium text-white hover:bg-brand-700" href="/login">Login</a>
{% endif %}
@@ -472,20 +472,10 @@
</div>
{% endif %}
{% if is_system_admin_user %}
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">System Wizard</label>
<a href="/wizards/system/firm/new"
class="inline-flex items-center rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white shadow-soft transition hover:bg-brand-700">
+ Create Firm
</a>
</div>
{% endif %}
<div class="text-xs text-slate-500">
Active Scope:
{{ current_firm_name }}
| {{ current_branch_name if active_branch_id else "All Branches" }}{% if active_financial_year %} | FY {{ active_financial_year }}{% endif %}
{{ current_branch_name if active_branch_id else "All Branches" }}{% if active_financial_year %} FY {{ active_financial_year }}{% endif %}
</div>
</div>
{% endif %}
@@ -557,7 +547,7 @@
wrapper.className = "overflow-hidden rounded-2xl border shadow-soft " + priorityClasses(alert.priority);
wrapper.innerHTML = `
<div class="flex items-start gap-3 p-4">
<div class="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-white/80 text-base">🔔</div>
<div class="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-white/80 text-base">🔔</div>
<div class="min-w-0 flex-1">
<div class="text-xs font-semibold uppercase tracking-wide opacity-75">New Alert</div>
<div class="mt-0.5 line-clamp-2 text-sm font-semibold"></div>
@@ -625,7 +615,3 @@
</body>
</html>