diff --git a/src/components/shared/DatePicker.vue b/src/components/shared/DatePicker.vue index 31208835a..9b3e242f6 100644 --- a/src/components/shared/DatePicker.vue +++ b/src/components/shared/DatePicker.vue @@ -31,6 +31,7 @@ v-model="formattedModel" :multiple="multiple" :label="label" + :density="density" :disabled="disabled" readonly :clearable="clearable" @@ -52,6 +53,7 @@ :hint="hint ?? defaults.hint" :prepend-inner-icon="icon" :variant="variant" + :density="density" :hide-details="hideDetails" :disabled="disabled" :rules="rules" @@ -79,6 +81,7 @@ const props = defineProps({ adjacentDays: { type: Boolean, default: false }, hideDetails: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, + density: { type: String, default: 'default' }, mode: { type: String, default: undefined }, // LOGIC/CONFIG diff --git a/src/components/utils/MainNav.vue b/src/components/utils/MainNav.vue index 486ec7ac7..b7bd764e0 100644 --- a/src/components/utils/MainNav.vue +++ b/src/components/utils/MainNav.vue @@ -152,6 +152,36 @@ const items = ref([ alias: ['audit'], icon: 'mdi-clipboard-check', route: 'audits', + subItems: [ + { + title: 'Old Audits', + icon: 'mdi-abacus', + route: 'old-audits', + permission: ['admin', 'manager'], + active: false + }, + // { + // title: 'Something idk', + // icon: 'mdi-clipboard-multiple', + // route: 'audits', + // permission: ['admin', 'manager'], + // active: false + // }, + { + title: 'Expense History', + icon: 'mdi-clipboard-text-multiple', + route: 'expenseHistory', + permission: ['admin', 'manager'], + active: false + }, + // { + // title: 'Employee History', + // icon: 'mdi-clipboard-play-multiple', + // route: 'employeeHistory', + // permission: ['admin', 'manager'], + // active: false + // } + ], permission: ['admin', 'manager'], active: false }, diff --git a/src/router.js b/src/router.js index 34fa6296d..480212356 100644 --- a/src/router.js +++ b/src/router.js @@ -8,6 +8,9 @@ import Employees from '@/views/Employees.vue'; import Employee from '@/views/Employee.vue'; import StatsDashboard from '@/views/StatsDashboard.vue'; import Audits from '@/views/Audits.vue'; +import AuditsV2 from '@/views/AuditsV2.vue'; +import ExpenseHistory from '@/views/ExpenseHistory.vue'; +import EmployeeHistory from '@/views/EmployeeHistory.vue'; import Expenses from '@/views/MyExpenses.vue'; import Help from '@/views/Help.vue'; import Reports from '@/views/Reports.vue'; @@ -63,10 +66,28 @@ const router = createRouter({ component: Contracts, beforeEnter: multiguard([requireAuth, isAdminOrManager]) }, + { + path: '/old-audits', + name: 'old-audits', + component: Audits, + beforeEnter: multiguard([requireAuth, isAdminOrManager]) + }, { path: '/audits', name: 'audits', - component: Audits, + component: AuditsV2, + beforeEnter: multiguard([requireAuth, isAdminOrManager]) + }, + { + path: '/expenseHistory', + name: 'expenseHistory', + component: ExpenseHistory, + beforeEnter: multiguard([requireAuth, isAdminOrManager]) + }, + { + path: '/employeeHistory', + name: 'employeeHistory', + component: EmployeeHistory, beforeEnter: multiguard([requireAuth, isAdminOrManager]) }, { diff --git a/src/shared/api.js b/src/shared/api.js index 2c661e1a0..5f3193d05 100644 --- a/src/shared/api.js +++ b/src/shared/api.js @@ -1,6 +1,9 @@ import axios from 'axios'; import { API_CONFIG } from './apiVariables'; import { getAccessToken } from '@/utils/auth'; +import { AuditRequestFilters } from './models/audits/audts'; + +// routes const EXPENSE_TYPES = 'expense-types'; const EXPENSES = 'expenses'; const EMPLOYEES = 'employees'; @@ -9,12 +12,13 @@ const UTILITY = 'utility'; const TIMESHEETS = 'timesheets'; const BASECAMP = 'basecamp'; const GOOGLE_MAPS = 'googleMaps'; -const AUDIT = 'audits'; +const AUDIT = 'auditsV2'; const RESUME = 'resume'; const CONTRACTS = 'contracts'; const HIGH_FIVES = 'highFives'; const PTO_CASH_OUTS = 'ptoCashOuts'; const TAGS = 'tags'; + const API_HOSTNAME = API_CONFIG.apiHostname; const API_PORT = API_CONFIG.apiPort; const PORT = API_PORT === '443' ? '' : `:${API_PORT}`; @@ -170,16 +174,22 @@ async function getAllEvents() { } // getAllEvents /** - * gets all the audits for a specific type in a specific range - * - * @param type - the type of the audit - * @param startDate - the start date of the wanted range - * @param endDate - the end date of the wanted range - * @return - the audit data + * Gets notification audits with specified filters + * @param {AuditRequestFilters?} filters Filters to query specific audits + * @returns {*} The api response or error + */ +async function getNotificationAudits(filters) { + return await execute('get', `/${AUDIT}/notification`, filters); +} // getNotificationAudits + +/** + * Gets CRUD audits with specified filters + * @param {AuditRequestFilters?} filters Filters to query specific audits + * @returns {*} The api response or error */ -async function getAudits(type, startDate, endDate) { - return await execute('get', `/${AUDIT}/${type}/${startDate}/${endDate}`); -} // getAudits +async function getCrudAudits(filters) { + return await execute('get', `/${AUDIT}/crud`, filters); +} // getCrudAudits /** * gets all items from a specific route @@ -516,7 +526,8 @@ export default { getAllEvents, getAllExpenseTypeExpenses, getAttachment, - getAudits, + getNotificationAudits, + getCrudAudits, getBasecampAvatars, getBasecampCampfires, getCity, diff --git a/src/shared/employeeUtils.js b/src/shared/employeeUtils.js index 4087ac508..6f2d2f051 100644 --- a/src/shared/employeeUtils.js +++ b/src/shared/employeeUtils.js @@ -145,7 +145,7 @@ export function nicknameAndLastName(employee) { * Gets an employee object based on the employee ID parameter * @param {Number} employeeId - employee ID * @param {Array} employees - list of employees - * @returns Employee object + * @returns {import('./models/employeeTypes').Employee} The employee */ export function getEmployeeByID(employeeId, employees) { return employees.find((e) => e.id == employeeId); diff --git a/src/shared/models/audits/audts.js b/src/shared/models/audits/audts.js new file mode 100644 index 000000000..5790058f9 --- /dev/null +++ b/src/shared/models/audits/audts.js @@ -0,0 +1,45 @@ +import { NotificationReason } from './notifications'; + +/** + * Enum for the type of audit + * @readonly + * @enum {string} + */ +export const AuditType = { + CRUD: 'crud', + LOGIN: 'login', + NOTIFICATION: 'notification', + ERROR: 'error' +}; + +export class AuditRequestFilters { + constructor(properties) { + if (!properties) return; + + /** + * The types of audits to include in the filter + * @type AuditType[] + */ + this.types = properties?.types; + + /** + * The uuid of the employee who caused the audit + * @type {string} + */ + this.actor = properties?.actor; + + /** + * The uuid of the employee whose data was changed, or (if the audit is a notification) received the notification + * @type {string} + */ + this.receiver = properties?.receiver; + + /** @type Date */ + this.startDate = properties?.startDate; + /** @type Date */ + this.endDate = properties?.endDate; + + /** @type NotificationReason */ + this.notifReason = properties?.notifReason; + } +} diff --git a/src/shared/models/audits/notifications.js b/src/shared/models/audits/notifications.js new file mode 100644 index 000000000..f85f62c06 --- /dev/null +++ b/src/shared/models/audits/notifications.js @@ -0,0 +1,58 @@ +/** + * Enum for the notification_reason type in the audits database + * @readonly + * @enum {string} + */ +export const NotificationReason = { + EXPENSE_REVISAL_REQUEST: 'expense_revisal_request', + EXPENSE_REJECTION: 'expense_rejection', + WEEKLY_TIME_REMINDER: 'weekly_timesheet_reminder', + MONTHLY_TIME_REMINDER: 'monthly_timesheet_reminder', + TRAINING_HOUR_EXCHANGE: 'training_hour_exchange', + HIGH_FIVE: 'high_five' +}; + +/** + * Model for a notification in the audits database + */ +export class Notification { + /** + * Creates a new model of a notificaiton + * @param {number} id Database ID + * @param {Date} createdAt When the notification was sent + * @param {string} receiverId The UUID of the employee that received the notification + * @param {string} sentTo Where the notification was sent (phone number, address, etc.) + * @param {NotificationReason} reason The reason the notification was sent (i.e. type of notification) + */ + constructor(id, createdAt, receiverId, sentTo, reason) { + /** + * The database id for this notification + * @type {number} + */ + this.id = id; + + /** + * The time this notification was sent + * @type {Date} + */ + this.createdAt = createdAt; + + /** + * The UUID of the employee who received the notification + * @type {string} + */ + this.receiverId = receiverId; + + /** + * The email or phone number to which this was sent + * @type {string} + */ + this.sentTo = sentTo; + + /** + * The reason/purpose of the notification + * @type {NotificationReason} + */ + this.reason = reason; + } +} diff --git a/src/views/AuditsV2.vue b/src/views/AuditsV2.vue new file mode 100644 index 000000000..65cc4c009 --- /dev/null +++ b/src/views/AuditsV2.vue @@ -0,0 +1,397 @@ + + + + + diff --git a/src/views/EmployeeHistory.vue b/src/views/EmployeeHistory.vue new file mode 100644 index 000000000..6da67d988 --- /dev/null +++ b/src/views/EmployeeHistory.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/src/views/ExpenseHistory.vue b/src/views/ExpenseHistory.vue new file mode 100644 index 000000000..cfa9a5ac4 --- /dev/null +++ b/src/views/ExpenseHistory.vue @@ -0,0 +1,288 @@ + + + + +