feat: add employee timing system, notification templates, and professor class plan sms

This commit is contained in:
2026-08-24 19:31:07 +03:30
parent 53fce86ad5
commit 282dd42422
18 changed files with 1152 additions and 175 deletions
@@ -0,0 +1,61 @@
// /components/employeeTimings/employeeTiming.test.js
'use strict';
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const {
computeStatus,
computeDurationMinutes,
computeDurationFormatted
} = require('./employeeTimingService');
describe('EmployeeTiming status and warning computations', () => {
it('returns "complete" when both entry and exit times are present', () => {
assert.equal(computeStatus('08:30', '17:00'), 'complete');
assert.equal(computeStatus('09:00', '14:30'), 'complete');
});
it('returns "missing_exit" when entry is present but exit is missing', () => {
assert.equal(computeStatus('08:30', ''), 'missing_exit');
assert.equal(computeStatus('08:30', null), 'missing_exit');
assert.equal(computeStatus('08:30', undefined), 'missing_exit');
assert.equal(computeStatus('08:30', ' '), 'missing_exit');
});
it('returns "missing_entry" when exit is present but entry is missing', () => {
assert.equal(computeStatus('', '17:00'), 'missing_entry');
assert.equal(computeStatus(null, '17:00'), 'missing_entry');
assert.equal(computeStatus(undefined, '17:00'), 'missing_entry');
assert.equal(computeStatus(' ', '17:00'), 'missing_entry');
});
it('returns "incomplete" when neither entry nor exit is present', () => {
assert.equal(computeStatus('', ''), 'incomplete');
assert.equal(computeStatus(null, null), 'incomplete');
assert.equal(computeStatus(undefined, undefined), 'incomplete');
});
});
describe('EmployeeTiming duration computations', () => {
it('calculates duration in minutes correctly for standard day hours', () => {
assert.equal(computeDurationMinutes('08:00', '16:30'), 510);
assert.equal(computeDurationMinutes('09:15', '10:45'), 90);
});
it('handles shift crossing midnight', () => {
assert.equal(computeDurationMinutes('22:00', '02:00'), 240);
});
it('returns null for missing times', () => {
assert.equal(computeDurationMinutes('', '17:00'), null);
assert.equal(computeDurationMinutes('08:00', ''), null);
assert.equal(computeDurationMinutes(null, null), null);
});
it('formats duration in Persian string', () => {
assert.equal(computeDurationFormatted(510), '8 ساعت و 30 دقیقه');
assert.equal(computeDurationFormatted(120), '2 ساعت');
assert.equal(computeDurationFormatted(45), '45 دقیقه');
assert.equal(computeDurationFormatted(null), '—');
});
});