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 @@
+
+
+
+
+
+
+
+
+
+ General filters
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ filters.auditType }} filters
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+ {{ data.status }}
+
+ {{ data.date }}
+
+
+
+ Click for more info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+ {{ determineStatus(audit) }}
+
+ {{ audit.date }}
+
+
+
+ Click for more info
+
+
+
+
+
+
+
+
+
+
+
+
+ Expense Status
+ {{ status }}
Before
+ {{ data }}
After
+ {{ data }}
+
+
+
+
+
+
+
+