This commit is contained in:
gsinghpal
2026-02-27 14:32:32 -05:00
parent b649246e81
commit b925766966
80 changed files with 7831 additions and 1041 deletions

View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<templates xml:space="preserve">
<t t-name="fusion_clock.Dashboard">
<div class="o_action">
<div class="container-fluid py-3">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0">Fusion Clock Dashboard</h2>
<button class="btn btn-outline-primary" t-on-click="onRefresh">
<i class="fa fa-refresh"/> Refresh
</button>
</div>
<t t-if="state.loading">
<div class="text-center py-5">
<i class="fa fa-spinner fa-spin fa-2x"/>
<p class="mt-2">Loading dashboard...</p>
</div>
</t>
<t t-if="state.error">
<div class="alert alert-danger">
<t t-esc="state.error"/>
</div>
</t>
<t t-if="!state.loading and !state.error">
<!-- Summary Cards -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="fclk-dash-card fclk-dash-card--total">
<div class="fclk-dash-card-icon">
<i class="fa fa-users"/>
</div>
<div class="fclk-dash-card-value"><t t-esc="state.total_employees"/></div>
<div class="fclk-dash-card-label">Total Employees</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="fclk-dash-card fclk-dash-card--present">
<div class="fclk-dash-card-icon">
<i class="fa fa-check-circle"/>
</div>
<div class="fclk-dash-card-value"><t t-esc="state.present_count"/></div>
<div class="fclk-dash-card-label">Present Today</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="fclk-dash-card fclk-dash-card--absent">
<div class="fclk-dash-card-icon">
<i class="fa fa-times-circle"/>
</div>
<div class="fclk-dash-card-value"><t t-esc="state.absent_count"/></div>
<div class="fclk-dash-card-label">Absent Today</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="fclk-dash-card fclk-dash-card--late">
<div class="fclk-dash-card-icon">
<i class="fa fa-clock-o"/>
</div>
<div class="fclk-dash-card-value"><t t-esc="state.late_count"/></div>
<div class="fclk-dash-card-label">Late Today</div>
</div>
</div>
</div>
<div class="row">
<!-- Currently Clocked In -->
<div class="col-md-8 mb-4">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Currently Clocked In</h5>
<span class="badge bg-success"><t t-esc="state.clocked_in.length"/> active</span>
</div>
<div class="card-body p-0">
<t t-if="state.clocked_in.length === 0">
<div class="text-center py-4 text-muted">
No employees currently clocked in
</div>
</t>
<t t-else="">
<table class="table table-sm mb-0">
<thead>
<tr>
<th>Employee</th>
<th>Clock-In</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<t t-foreach="state.clocked_in" t-as="emp" t-key="emp_index">
<tr>
<td><t t-esc="emp.employee"/></td>
<td><t t-esc="emp.check_in"/></td>
<td><t t-esc="emp.location"/></td>
</tr>
</t>
</tbody>
</table>
</t>
</div>
</div>
</div>
<!-- Alerts Panel -->
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Alerts</h5>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3 cursor-pointer"
t-on-click="onViewActivityLogs">
<span><i class="fa fa-exclamation-circle text-warning me-2"/>Pending Reasons</span>
<span class="badge bg-warning"><t t-esc="state.pending_reasons"/></span>
</div>
<div class="d-flex justify-content-between align-items-center mb-3 cursor-pointer"
t-on-click="onViewCorrections">
<span><i class="fa fa-edit text-info me-2"/>Pending Corrections</span>
<span class="badge bg-info"><t t-esc="state.pending_corrections"/></span>
</div>
<div class="d-flex justify-content-between align-items-center cursor-pointer"
t-on-click="onViewPenalties">
<span><i class="fa fa-clock-o text-danger me-2"/>Late Today</span>
<span class="badge bg-danger"><t t-esc="state.late_count"/></span>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="card mt-3">
<div class="card-header">
<h5 class="mb-0">Quick Actions</h5>
</div>
<div class="card-body">
<button class="btn btn-outline-primary w-100 mb-2" t-on-click="onViewAttendances">
<i class="fa fa-list me-1"/> View All Attendances
</button>
<button class="btn btn-outline-secondary w-100" t-on-click="onViewActivityLogs">
<i class="fa fa-history me-1"/> Activity Logs
</button>
</div>
</div>
</div>
</div>
</t>
</div>
</div>
</t>
</templates>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<templates xml:space="preserve">
<!-- Interactive Map Widget -->
<t t-name="fusion_clock.LocationMap">
<div class="fclk-map-widget">
<div t-if="state.loading" class="fclk-map-loading">
<i class="fa fa-circle-o-notch fa-spin"/> Loading map...
</div>
<div t-if="state.error" class="fclk-map-error">
<i class="fa fa-exclamation-triangle"/> <t t-esc="state.error"/>
</div>
<!-- ALWAYS in the DOM so the ref is available at mount time.
Hidden via inline display:none until the map is ready. -->
<div t-ref="mapContainer"
class="fclk-map-container"
t-att-style="state.mapVisible ? 'width:100%;height:400px;border-radius:8px;' : 'display:none;'"/>
<div t-if="state.mapVisible and !props.readonly" class="fclk-map-hint">
<i class="fa fa-hand-pointer-o"/> Click the map or drag the marker to fine-tune the location
</div>
</div>
</t>
<!-- Places Autocomplete Widget -->
<t t-name="fusion_clock.PlacesAutocomplete">
<t t-if="isReadonly">
<span t-esc="props.record.data[props.name] || ''"/>
</t>
<t t-else="">
<input t-ref="addressInput"
type="text"
class="o_input fclk-places-input"
t-att-value="state.value"
t-on-input="onInput"
t-on-change="onChange"
placeholder="Start typing an address..."/>
</t>
</t>
</templates>

View File

@@ -68,20 +68,91 @@
<!-- Floating Action Button -->
<button t-attf-class="fclk-fab-btn {{ state.isCheckedIn ? 'fclk-fab-btn--active' : '' }} {{ state.expanded ? 'fclk-fab-btn--open' : '' }}"
t-on-click="togglePanel">
<!-- Ripple rings (always animate) -->
<span t-if="state.isCheckedIn" class="fclk-fab-ripple-ring fclk-fab-ripple-ring--1"/>
<span t-if="state.isCheckedIn" class="fclk-fab-ripple-ring fclk-fab-ripple-ring--2"/>
<span t-if="state.isCheckedIn" class="fclk-fab-ripple-ring fclk-fab-ripple-ring--3"/>
<!-- Icon -->
<span class="fclk-fab-icon">
<i t-if="!state.expanded" class="fa fa-clock-o"/>
<i t-else="" class="fa fa-times"/>
</span>
<!-- Mini timer badge -->
<span t-if="state.isCheckedIn and !state.expanded" class="fclk-fab-badge">
<t t-esc="state.timerDisplay"/>
</span>
</button>
<!-- Missed Clock-Out Reason Dialog -->
<div t-if="state.showReasonDialog" class="fclk-fab-dialog-overlay">
<div class="fclk-fab-dialog-backdrop" t-on-click="cancelReason"/>
<div class="fclk-fab-dialog">
<div class="fclk-fab-dialog-header fclk-fab-dialog-header--warning">
<div class="fclk-fab-dialog-icon">
<i class="fa fa-exclamation-triangle"/>
</div>
<h4 class="fclk-fab-dialog-title">Missed Clock-Out</h4>
<p class="fclk-fab-dialog-subtitle">You didn't clock out on your last shift. Please provide details before continuing.</p>
</div>
<div class="fclk-fab-dialog-body">
<div class="fclk-fab-dialog-field">
<label class="fclk-fab-dialog-label">
<i class="fa fa-comment-o"/> Reason <span class="fclk-fab-dialog-required">*</span>
</label>
<textarea class="fclk-fab-dialog-input" rows="3"
placeholder="Please explain why you didn't clock out..."
t-on-input="onReasonTextInput"
t-att-value="state.reasonText"/>
</div>
<div class="fclk-fab-dialog-field">
<label class="fclk-fab-dialog-label">
<i class="fa fa-clock-o"/> Departure Time
</label>
<input type="datetime-local" class="fclk-fab-dialog-input"
t-on-input="onReasonTimeInput"
t-att-value="state.reasonTime"/>
<span class="fclk-fab-dialog-hint">When did you actually leave? (optional)</span>
</div>
</div>
<div class="fclk-fab-dialog-footer">
<button class="fclk-fab-dialog-btn fclk-fab-dialog-btn--cancel" t-on-click="cancelReason">Cancel</button>
<button class="fclk-fab-dialog-btn fclk-fab-dialog-btn--submit" t-on-click="submitReason"
t-att-disabled="state.reasonSubmitting">
<t t-if="state.reasonSubmitting"><i class="fa fa-circle-o-notch fa-spin"/> Submitting...</t>
<t t-else=""><i class="fa fa-check"/> Submit Reason</t>
</button>
</div>
</div>
</div>
<!-- Clock-Out Confirmation Dialog -->
<div t-if="state.showClockoutConfirm" class="fclk-fab-dialog-overlay">
<div class="fclk-fab-dialog-backdrop" t-on-click="cancelClockOut"/>
<div class="fclk-fab-dialog fclk-fab-dialog--compact">
<div class="fclk-fab-dialog-header fclk-fab-dialog-header--danger">
<div class="fclk-fab-dialog-icon">
<i class="fa fa-stop-circle"/>
</div>
<h4 class="fclk-fab-dialog-title">Clock Out?</h4>
<p class="fclk-fab-dialog-subtitle">Are you sure you want to end your current shift?</p>
</div>
<div class="fclk-fab-dialog-body">
<div class="fclk-fab-dialog-summary">
<div class="fclk-fab-dialog-summary-row">
<span class="fclk-fab-dialog-summary-label">Clocked in at</span>
<span class="fclk-fab-dialog-summary-value" t-esc="confirmCheckinDisplay"/>
</div>
<div class="fclk-fab-dialog-summary-row">
<span class="fclk-fab-dialog-summary-label">Duration</span>
<span class="fclk-fab-dialog-summary-value" t-esc="confirmDurationDisplay"/>
</div>
</div>
</div>
<div class="fclk-fab-dialog-footer">
<button class="fclk-fab-dialog-btn fclk-fab-dialog-btn--cancel" t-on-click="cancelClockOut">Cancel</button>
<button class="fclk-fab-dialog-btn fclk-fab-dialog-btn--danger" t-on-click="confirmClockOut">
<i class="fa fa-stop-circle-o"/> Confirm Clock Out
</button>
</div>
</div>
</div>
</div>
</t>