Autosave: 20260203-121839
This commit is contained in:
parent
290810a317
commit
88aaaf8f2d
@ -1,4 +1,3 @@
|
||||
|
||||
const db = require('../models');
|
||||
const FileDBApi = require('./file');
|
||||
const crypto = require('crypto');
|
||||
@ -84,6 +83,18 @@ module.exports = class UsersDBApi {
|
||||
||
|
||||
null
|
||||
,
|
||||
|
||||
matriculePaie: data.data.matriculePaie || null,
|
||||
workdayId: data.data.workdayId || null,
|
||||
productionSite: data.data.productionSite || null,
|
||||
remoteWork: data.data.remoteWork || null,
|
||||
hiringDate: data.data.hiringDate || null,
|
||||
positionEntryDate: data.data.positionEntryDate || null,
|
||||
departureDate: data.data.departureDate || null,
|
||||
service: data.data.service || null,
|
||||
position: data.data.position || null,
|
||||
team: data.data.team || null,
|
||||
departmentId: data.data.department || data.data.departmentId || null,
|
||||
|
||||
importHash: data.data.importHash || null,
|
||||
createdById: currentUser.id,
|
||||
@ -204,6 +215,18 @@ module.exports = class UsersDBApi {
|
||||
||
|
||||
null
|
||||
,
|
||||
|
||||
matriculePaie: item.matriculePaie || null,
|
||||
workdayId: item.workdayId || null,
|
||||
productionSite: item.productionSite || null,
|
||||
remoteWork: item.remoteWork || null,
|
||||
hiringDate: item.hiringDate || null,
|
||||
positionEntryDate: item.positionEntryDate || null,
|
||||
departureDate: item.departureDate || null,
|
||||
service: item.service || null,
|
||||
position: item.position || null,
|
||||
team: item.team || null,
|
||||
departmentId: item.department || item.departmentId || null,
|
||||
|
||||
importHash: item.importHash || null,
|
||||
createdById: currentUser.id,
|
||||
@ -297,6 +320,19 @@ module.exports = class UsersDBApi {
|
||||
|
||||
|
||||
if (data.provider !== undefined) updatePayload.provider = data.provider;
|
||||
|
||||
if (data.matriculePaie !== undefined) updatePayload.matriculePaie = data.matriculePaie;
|
||||
if (data.workdayId !== undefined) updatePayload.workdayId = data.workdayId;
|
||||
if (data.productionSite !== undefined) updatePayload.productionSite = data.productionSite;
|
||||
if (data.remoteWork !== undefined) updatePayload.remoteWork = data.remoteWork;
|
||||
if (data.hiringDate !== undefined) updatePayload.hiringDate = data.hiringDate;
|
||||
if (data.positionEntryDate !== undefined) updatePayload.positionEntryDate = data.positionEntryDate;
|
||||
if (data.departureDate !== undefined) updatePayload.departureDate = data.departureDate;
|
||||
if (data.service !== undefined) updatePayload.service = data.service;
|
||||
if (data.position !== undefined) updatePayload.position = data.position;
|
||||
if (data.team !== undefined) updatePayload.team = data.team;
|
||||
if (data.department !== undefined) updatePayload.departmentId = data.department;
|
||||
if (data.departmentId !== undefined) updatePayload.departmentId = data.departmentId;
|
||||
|
||||
|
||||
updatePayload.updatedById = currentUser.id;
|
||||
@ -427,6 +463,10 @@ module.exports = class UsersDBApi {
|
||||
output.avatar = await users.getAvatar({
|
||||
transaction
|
||||
});
|
||||
|
||||
output.department = await users.getDepartment({
|
||||
transaction
|
||||
});
|
||||
|
||||
|
||||
output.app_role = await users.getApp_role({
|
||||
@ -500,6 +540,11 @@ module.exports = class UsersDBApi {
|
||||
as: 'avatar',
|
||||
},
|
||||
|
||||
{
|
||||
model: db.departments,
|
||||
as: 'department',
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
if (filter) {
|
||||
@ -554,6 +599,28 @@ module.exports = class UsersDBApi {
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.matriculePaie) {
|
||||
where = {
|
||||
...where,
|
||||
[Op.and]: Utils.ilike(
|
||||
'users',
|
||||
'matriculePaie',
|
||||
filter.matriculePaie,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.workdayId) {
|
||||
where = {
|
||||
...where,
|
||||
[Op.and]: Utils.ilike(
|
||||
'users',
|
||||
'workdayId',
|
||||
filter.workdayId,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.password) {
|
||||
where = {
|
||||
@ -598,6 +665,13 @@ module.exports = class UsersDBApi {
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.department) {
|
||||
where = {
|
||||
...where,
|
||||
departmentId: Utils.uuid(filter.department),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -775,12 +849,17 @@ module.exports = class UsersDBApi {
|
||||
'firstName',
|
||||
query,
|
||||
),
|
||||
Utils.ilike(
|
||||
'users',
|
||||
'lastName',
|
||||
query,
|
||||
),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const records = await db.users.findAll({
|
||||
attributes: [ 'id', 'firstName' ],
|
||||
attributes: [ 'id', 'firstName', 'lastName' ],
|
||||
where,
|
||||
limit: limit ? Number(limit) : undefined,
|
||||
offset: offset ? Number(offset) : undefined,
|
||||
@ -789,7 +868,7 @@ module.exports = class UsersDBApi {
|
||||
|
||||
return records.map((record) => ({
|
||||
id: record.id,
|
||||
label: record.firstName,
|
||||
label: `${record.firstName} ${record.lastName}`,
|
||||
}));
|
||||
}
|
||||
|
||||
@ -943,5 +1022,4 @@ module.exports = class UsersDBApi {
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
module.exports = {
|
||||
production: {
|
||||
dialect: 'postgres',
|
||||
@ -12,11 +10,12 @@ module.exports = {
|
||||
seederStorage: 'sequelize',
|
||||
},
|
||||
development: {
|
||||
username: 'postgres',
|
||||
username: process.env.DB_USER || 'postgres',
|
||||
dialect: 'postgres',
|
||||
password: '',
|
||||
database: 'db_gestion_entr_es_sorties',
|
||||
password: process.env.DB_PASS || '',
|
||||
database: process.env.DB_NAME || 'db_gestion_entr_es_sorties',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
logging: console.log,
|
||||
seederStorage: 'sequelize',
|
||||
},
|
||||
@ -30,4 +29,4 @@ module.exports = {
|
||||
logging: console.log,
|
||||
seederStorage: 'sequelize',
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,37 @@
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.sequelize.query(`
|
||||
INSERT INTO "rolesPermissionsPermissions" ("createdAt", "updatedAt", "roles_permissionsId", "permissionId")
|
||||
SELECT NOW(), NOW(), r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.name = 'Public'
|
||||
AND p.name IN ('READ_USERS', 'CREATE_TIME_ENTRIES')
|
||||
ON CONFLICT ("roles_permissionsId", "permissionId") DO NOTHING;
|
||||
`, { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.sequelize.query(`
|
||||
DELETE FROM "rolesPermissionsPermissions"
|
||||
WHERE "roles_permissionsId" IN (SELECT id FROM roles WHERE name = 'Public')
|
||||
AND "permissionId" IN (SELECT id FROM permissions WHERE name IN ('READ_USERS', 'CREATE_TIME_ENTRIES'));
|
||||
`, { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
60
backend/src/db/migrations/20260203110000-add-user-fields.js
Normal file
60
backend/src/db/migrations/20260203110000-add-user-fields.js
Normal file
@ -0,0 +1,60 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async up(queryInterface, Sequelize) {
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.addColumn('users', 'matriculePaie', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'workdayId', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'productionSite', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'remoteWork', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'hiringDate', { type: Sequelize.DataTypes.DATE }, { transaction });
|
||||
await queryInterface.addColumn('users', 'positionEntryDate', { type: Sequelize.DataTypes.DATE }, { transaction });
|
||||
await queryInterface.addColumn('users', 'departureDate', { type: Sequelize.DataTypes.DATE }, { transaction });
|
||||
await queryInterface.addColumn('users', 'service', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'position', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'team', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||
await queryInterface.addColumn('users', 'departmentId', {
|
||||
type: Sequelize.DataTypes.UUID,
|
||||
references: {
|
||||
model: 'departments',
|
||||
key: 'id',
|
||||
},
|
||||
allowNull: true,
|
||||
}, { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async down(queryInterface, Sequelize) {
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.removeColumn('users', 'matriculePaie', { transaction });
|
||||
await queryInterface.removeColumn('users', 'workdayId', { transaction });
|
||||
await queryInterface.removeColumn('users', 'productionSite', { transaction });
|
||||
await queryInterface.removeColumn('users', 'remoteWork', { transaction });
|
||||
await queryInterface.removeColumn('users', 'hiringDate', { transaction });
|
||||
await queryInterface.removeColumn('users', 'positionEntryDate', { transaction });
|
||||
await queryInterface.removeColumn('users', 'departureDate', { transaction });
|
||||
await queryInterface.removeColumn('users', 'service', { transaction });
|
||||
await queryInterface.removeColumn('users', 'position', { transaction });
|
||||
await queryInterface.removeColumn('users', 'team', { transaction });
|
||||
await queryInterface.removeColumn('users', 'departmentId', { transaction });
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -14,94 +14,96 @@ module.exports = function(sequelize, DataTypes) {
|
||||
primaryKey: true,
|
||||
},
|
||||
|
||||
firstName: {
|
||||
firstName: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
lastName: {
|
||||
lastName: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
phoneNumber: {
|
||||
phoneNumber: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
email: {
|
||||
email: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
disabled: {
|
||||
disabled: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
password: {
|
||||
password: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
emailVerified: {
|
||||
emailVerified: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
|
||||
allowNull: false,
|
||||
defaultValue: false,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
emailVerificationToken: {
|
||||
emailVerificationToken: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
emailVerificationTokenExpiresAt: {
|
||||
emailVerificationTokenExpiresAt: {
|
||||
type: DataTypes.DATE,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
passwordResetToken: {
|
||||
passwordResetToken: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
passwordResetTokenExpiresAt: {
|
||||
passwordResetTokenExpiresAt: {
|
||||
type: DataTypes.DATE,
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
provider: {
|
||||
provider: {
|
||||
type: DataTypes.TEXT,
|
||||
|
||||
|
||||
},
|
||||
|
||||
matriculePaie: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
workdayId: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
productionSite: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
remoteWork: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
hiringDate: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
|
||||
positionEntryDate: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
|
||||
departureDate: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
|
||||
service: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
position: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
team: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
importHash: {
|
||||
@ -137,13 +139,6 @@ provider: {
|
||||
through: 'usersCustom_permissionsPermissions',
|
||||
});
|
||||
|
||||
|
||||
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
db.users.hasMany(db.departments, {
|
||||
as: 'departments_manager',
|
||||
foreignKey: {
|
||||
@ -152,6 +147,13 @@ provider: {
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
db.users.belongsTo(db.departments, {
|
||||
as: 'department',
|
||||
foreignKey: {
|
||||
name: 'departmentId',
|
||||
},
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
db.users.hasMany(db.time_entries, {
|
||||
as: 'time_entries_employee',
|
||||
@ -179,12 +181,6 @@ provider: {
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
|
||||
|
||||
//end loop
|
||||
|
||||
|
||||
|
||||
db.users.belongsTo(db.roles, {
|
||||
as: 'app_role',
|
||||
foreignKey: {
|
||||
@ -193,8 +189,6 @@ provider: {
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
|
||||
|
||||
db.users.hasMany(db.file, {
|
||||
as: 'avatar',
|
||||
foreignKey: 'belongsToId',
|
||||
@ -247,7 +241,7 @@ provider: {
|
||||
|
||||
|
||||
function trimStringFields(users) {
|
||||
users.email = users.email.trim();
|
||||
if (users.email) users.email = users.email.trim();
|
||||
|
||||
users.firstName = users.firstName
|
||||
? users.firstName.trim()
|
||||
@ -258,5 +252,4 @@ function trimStringFields(users) {
|
||||
: null;
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const app = express();
|
||||
@ -93,7 +92,7 @@ app.use('/api/pexels', pexelsRoutes);
|
||||
app.enable('trust proxy');
|
||||
|
||||
|
||||
app.use('/api/users', passport.authenticate('jwt', {session: false}), usersRoutes);
|
||||
app.use('/api/users', usersRoutes);
|
||||
|
||||
app.use('/api/roles', passport.authenticate('jwt', {session: false}), rolesRoutes);
|
||||
|
||||
@ -101,7 +100,7 @@ app.use('/api/permissions', passport.authenticate('jwt', {session: false}), perm
|
||||
|
||||
app.use('/api/departments', passport.authenticate('jwt', {session: false}), departmentsRoutes);
|
||||
|
||||
app.use('/api/time_entries', passport.authenticate('jwt', {session: false}), time_entriesRoutes);
|
||||
app.use('/api/time_entries', time_entriesRoutes);
|
||||
|
||||
app.use('/api/import_jobs', passport.authenticate('jwt', {session: false}), import_jobsRoutes);
|
||||
|
||||
@ -151,4 +150,4 @@ db.sequelize.sync().then(function () {
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
module.exports = app;
|
||||
@ -1,6 +1,5 @@
|
||||
import React, {useEffect, useRef} from 'react'
|
||||
import React, {useEffect, useRef, useState} from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { mdiChevronUp, mdiChevronDown } from '@mdi/js'
|
||||
import BaseDivider from './BaseDivider'
|
||||
import BaseIcon from './BaseIcon'
|
||||
@ -129,4 +128,4 @@ export default function NavBarItem({ item }: Props) {
|
||||
}
|
||||
|
||||
return <div className={componentClass} ref={excludedRef}>{NavBarItemComponentContents}</div>
|
||||
}
|
||||
}
|
||||
@ -20,27 +20,22 @@ type Params = (id: string) => void;
|
||||
export const loadColumns = async (
|
||||
onDelete: Params,
|
||||
entityName: string,
|
||||
|
||||
user
|
||||
|
||||
) => {
|
||||
async function callOptionsApi(entityName: string) {
|
||||
|
||||
if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
|
||||
|
||||
try {
|
||||
const data = await axios(`/${entityName}/autocomplete?limit=100`);
|
||||
return data.data;
|
||||
const data = await axios(`/${entityName}/autocomplete?limit=100`);
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return [];
|
||||
console.log(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const hasUpdatePermission = hasPermission(user, 'UPDATE_USERS')
|
||||
|
||||
return [
|
||||
|
||||
{
|
||||
field: 'firstName',
|
||||
headerName: 'First Name',
|
||||
@ -49,13 +44,8 @@ export const loadColumns = async (
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'lastName',
|
||||
headerName: 'Last Name',
|
||||
@ -64,122 +54,96 @@ export const loadColumns = async (
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'phoneNumber',
|
||||
headerName: 'Phone Number',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'email',
|
||||
headerName: 'E-Mail',
|
||||
flex: 1,
|
||||
minWidth: 150,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
{
|
||||
field: 'matriculePaie',
|
||||
headerName: 'Matricule Paie',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'workdayId',
|
||||
headerName: 'WD ID',
|
||||
flex: 1,
|
||||
minWidth: 100,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
{
|
||||
field: 'department',
|
||||
headerName: 'Département',
|
||||
flex: 1,
|
||||
minWidth: 150,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
sortable: false,
|
||||
type: 'singleSelect',
|
||||
getOptionValue: (value: any) => value?.id,
|
||||
getOptionLabel: (value: any) => value?.name,
|
||||
valueOptions: await callOptionsApi('departments'),
|
||||
valueGetter: (params: GridValueGetterParams) =>
|
||||
params?.row?.department?.name || params?.row?.departmentId,
|
||||
},
|
||||
{
|
||||
field: 'service',
|
||||
headerName: 'Service',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
{
|
||||
field: 'position',
|
||||
headerName: 'Poste',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
{
|
||||
field: 'productionSite',
|
||||
headerName: 'Site de production',
|
||||
flex: 1,
|
||||
minWidth: 150,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
{
|
||||
field: 'disabled',
|
||||
headerName: 'Disabled',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
minWidth: 100,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
type: 'boolean',
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'avatar',
|
||||
headerName: 'Avatar',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
editable: false,
|
||||
sortable: false,
|
||||
renderCell: (params: GridValueGetterParams) => (
|
||||
<ImageField
|
||||
name={'Avatar'}
|
||||
image={params?.row?.avatar}
|
||||
className='w-24 h-24 mx-auto lg:w-6 lg:h-6'
|
||||
/>
|
||||
),
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'app_role',
|
||||
headerName: 'App Role',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
|
||||
sortable: false,
|
||||
type: 'singleSelect',
|
||||
getOptionValue: (value: any) => value?.id,
|
||||
getOptionLabel: (value: any) => value?.label,
|
||||
valueOptions: await callOptionsApi('roles'),
|
||||
valueGetter: (params: GridValueGetterParams) =>
|
||||
params?.value?.id ?? params?.value,
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'custom_permissions',
|
||||
headerName: 'Custom Permissions',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
editable: false,
|
||||
sortable: false,
|
||||
type: 'singleSelect',
|
||||
valueFormatter: ({ value }) =>
|
||||
dataFormatter.permissionsManyListFormatter(value).join(', '),
|
||||
renderEditCell: (params) => (
|
||||
<DataGridMultiSelect {...params} entityName={'permissions'}/>
|
||||
),
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
field: 'actions',
|
||||
type: 'actions',
|
||||
@ -187,7 +151,6 @@ export const loadColumns = async (
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
getActions: (params: GridRowParams) => {
|
||||
|
||||
return [
|
||||
<div key={params?.row?.id}>
|
||||
<ListActionsPopover
|
||||
@ -195,13 +158,11 @@ export const loadColumns = async (
|
||||
itemId={params?.row?.id}
|
||||
pathEdit={`/users/users-edit/?id=${params?.row?.id}`}
|
||||
pathView={`/users/users-view/?id=${params?.row?.id}`}
|
||||
|
||||
hasUpdatePermission={hasUpdatePermission}
|
||||
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
@ -1,5 +1,4 @@
|
||||
import React, { ReactNode, useEffect } from 'react'
|
||||
import { useState } from 'react'
|
||||
import React, { ReactNode, useEffect, useState } from 'react'
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js'
|
||||
import menuAside from '../menuAside'
|
||||
@ -126,4 +125,4 @@ export default function LayoutAuthenticated({
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -7,15 +7,28 @@ const menuAside: MenuAsideItem[] = [
|
||||
icon: icon.mdiViewDashboardOutline,
|
||||
label: 'Dashboard',
|
||||
},
|
||||
|
||||
{
|
||||
href: '/check-in',
|
||||
label: 'Pointage Entrée',
|
||||
icon: icon.mdiClockIn,
|
||||
permissions: 'CREATE_TIME_ENTRIES'
|
||||
},
|
||||
{
|
||||
href: '/users/users-list',
|
||||
label: 'Users',
|
||||
label: 'Collaborateurs',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiAccountGroup ?? icon.mdiTable,
|
||||
permissions: 'READ_USERS'
|
||||
},
|
||||
{
|
||||
href: '/time_entries/time_entries-list',
|
||||
label: 'Présences',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: 'mdiClock' in icon ? icon['mdiClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_TIME_ENTRIES'
|
||||
},
|
||||
{
|
||||
href: '/roles/roles-list',
|
||||
label: 'Roles',
|
||||
@ -40,14 +53,6 @@ const menuAside: MenuAsideItem[] = [
|
||||
icon: 'mdiOfficeBuilding' in icon ? icon['mdiOfficeBuilding' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_DEPARTMENTS'
|
||||
},
|
||||
{
|
||||
href: '/time_entries/time_entries-list',
|
||||
label: 'Time entries',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: 'mdiClock' in icon ? icon['mdiClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_TIME_ENTRIES'
|
||||
},
|
||||
{
|
||||
href: '/import_jobs/import_jobs-list',
|
||||
label: 'Import jobs',
|
||||
@ -69,8 +74,6 @@ const menuAside: MenuAsideItem[] = [
|
||||
label: 'Profile',
|
||||
icon: icon.mdiAccountCircle,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
href: '/api-docs',
|
||||
target: '_blank',
|
||||
@ -80,4 +83,4 @@ const menuAside: MenuAsideItem[] = [
|
||||
},
|
||||
]
|
||||
|
||||
export default menuAside
|
||||
export default menuAside
|
||||
213
frontend/src/pages/check-in.tsx
Normal file
213
frontend/src/pages/check-in.tsx
Normal file
@ -0,0 +1,213 @@
|
||||
import { mdiClockIn, mdiAccountSearch, mdiCalendarClock, mdiCardAccountDetailsOutline, mdiCheckCircle, mdiCardAccountDetails } from '@mdi/js'
|
||||
import Head from 'next/head'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import CardBox from '../components/CardBox'
|
||||
import LayoutGuest from '../layouts/Guest'
|
||||
import SectionMain from '../components/SectionMain'
|
||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
|
||||
import { getPageTitle } from '../config'
|
||||
|
||||
import { Field, Form, Formik, useFormikContext } from 'formik'
|
||||
import FormField from '../components/FormField'
|
||||
import BaseDivider from '../components/BaseDivider'
|
||||
import BaseButtons from '../components/BaseButtons'
|
||||
import BaseButton from '../components/BaseButton'
|
||||
import { SelectField } from '../components/SelectField'
|
||||
import NotificationBar from '../components/NotificationBar'
|
||||
import BaseIcon from '../components/BaseIcon'
|
||||
|
||||
import { create } from '../stores/time_entries/time_entriesSlice'
|
||||
import { useAppDispatch } from '../stores/hooks'
|
||||
import moment from 'moment'
|
||||
import axios from 'axios'
|
||||
|
||||
const initialValues = {
|
||||
employee: '',
|
||||
start_time: moment().format('YYYY-MM-DDTHH:mm'),
|
||||
badge_number: '',
|
||||
status: 'pending',
|
||||
}
|
||||
|
||||
const EmployeeDetails = () => {
|
||||
const { values } = useFormikContext<any>()
|
||||
const [employeeData, setEmployeeData] = useState<any>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (values.employee) {
|
||||
setLoading(true)
|
||||
axios.get(`/users/${values.employee}`)
|
||||
.then(res => {
|
||||
setEmployeeData(res.data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
setEmployeeData(null)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
} else {
|
||||
setEmployeeData(null)
|
||||
}
|
||||
}, [values.employee])
|
||||
|
||||
if (loading) return <div className="mt-4 animate-pulse text-gray-500 text-sm">Chargement des informations du collaborateur...</div>
|
||||
if (!employeeData) return null
|
||||
|
||||
return (
|
||||
<div className="mt-4 p-4 bg-gray-50 dark:bg-slate-800 rounded-lg border border-gray-200 dark:border-slate-700">
|
||||
<div className="flex items-center mb-3 text-blue-600 dark:text-blue-400">
|
||||
<BaseIcon path={mdiCardAccountDetails} size={24} className="mr-2" />
|
||||
<span className="font-bold text-lg">Informations Collaborateur</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<p className="text-gray-500">Nom & Prénom:</p>
|
||||
<p className="font-semibold">{employeeData.firstName} {employeeData.lastName}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Département:</p>
|
||||
<p className="font-semibold">{employeeData.department?.name || 'Non défini'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Matricule Paie:</p>
|
||||
<p className="font-semibold">{employeeData.matriculePaie || '-'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Workday ID:</p>
|
||||
<p className="font-semibold">{employeeData.workdayId || '-'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Site de production:</p>
|
||||
<p className="font-semibold">{employeeData.productionSite || '-'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Télétravail:</p>
|
||||
<p className="font-semibold">{employeeData.remoteWork || '-'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Service:</p>
|
||||
<p className="font-semibold">{employeeData.service || '-'}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-gray-500">Poste:</p>
|
||||
<p className="font-semibold">{employeeData.position || '-'}</p>
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<p className="text-gray-500">Équipe (N+1):</p>
|
||||
<p className="font-semibold">{employeeData.team || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const CheckIn = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
const handleSubmit = async (data, { resetForm }) => {
|
||||
setIsSuccess(false)
|
||||
setError(null)
|
||||
try {
|
||||
const resultAction = await dispatch(create(data))
|
||||
if (create.fulfilled.match(resultAction)) {
|
||||
setIsSuccess(true)
|
||||
resetForm()
|
||||
} else {
|
||||
setError("Une erreur est survenue lors de l'enregistrement.")
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Une erreur est survenue lors de l'enregistrement.")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('Enregistrement Entrée')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiClockIn} title="Enregistrement Entrée" main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
{isSuccess && (
|
||||
<NotificationBar color="success" icon={mdiCheckCircle}>
|
||||
L'entrée a été enregistrée avec succès.
|
||||
</NotificationBar>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<NotificationBar color="danger" icon={mdiCheckCircle}>
|
||||
{error}
|
||||
</NotificationBar>
|
||||
)}
|
||||
|
||||
<CardBox>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<FormField label="Collaborateur" labelFor="employee" icons={[mdiAccountSearch]}>
|
||||
<Field
|
||||
name="employee"
|
||||
id="employee"
|
||||
component={SelectField}
|
||||
options={[]}
|
||||
itemRef={'users'}
|
||||
showField={'lastName'}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<EmployeeDetails />
|
||||
|
||||
<BaseDivider />
|
||||
|
||||
<FormField label="Heure d'entrée" icons={[mdiCalendarClock]}>
|
||||
<Field type="datetime-local" name="start_time" placeholder="Heure d'entrée" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Numéro de badge provisoire" icons={[mdiCardAccountDetailsOutline]}>
|
||||
<Field name="badge_number" placeholder="Ex: 12345" />
|
||||
</FormField>
|
||||
|
||||
<BaseDivider />
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButton
|
||||
type="submit"
|
||||
color="info"
|
||||
label={isSubmitting ? "Enregistrement..." : "Enregistrer l'entrée"}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
<BaseButton
|
||||
type="reset"
|
||||
color="info"
|
||||
outline
|
||||
label="Réinitialiser"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</BaseButtons>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
CheckIn.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<LayoutGuest>
|
||||
{page}
|
||||
</LayoutGuest>
|
||||
)
|
||||
}
|
||||
|
||||
export default CheckIn
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import Head from 'next/head';
|
||||
@ -7,13 +6,12 @@ import BaseButton from '../components/BaseButton';
|
||||
import CardBox from '../components/CardBox';
|
||||
import SectionFullScreen from '../components/SectionFullScreen';
|
||||
import LayoutGuest from '../layouts/Guest';
|
||||
import BaseDivider from '../components/BaseDivider';
|
||||
import BaseButtons from '../components/BaseButtons';
|
||||
import { getPageTitle } from '../config';
|
||||
import { useAppSelector } from '../stores/hooks';
|
||||
import CardBoxComponentTitle from "../components/CardBoxComponentTitle";
|
||||
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
||||
|
||||
import { mdiClockIn, mdiLogin } from '@mdi/js';
|
||||
|
||||
export default function Starter() {
|
||||
const [illustrationImage, setIllustrationImage] = useState({
|
||||
@ -111,7 +109,7 @@ export default function Starter() {
|
||||
}
|
||||
>
|
||||
<Head>
|
||||
<title>{getPageTitle('Starter Page')}</title>
|
||||
<title>{getPageTitle('Gestion Entrées Sorties')}</title>
|
||||
</Head>
|
||||
|
||||
<SectionFullScreen bg='violet'>
|
||||
@ -128,22 +126,31 @@ export default function Starter() {
|
||||
: null}
|
||||
<div className='flex items-center justify-center flex-col space-y-4 w-full lg:w-full'>
|
||||
<CardBox className='w-full md:w-3/5 lg:w-2/3'>
|
||||
<CardBoxComponentTitle title="Welcome to your Gestion Entrées Sorties app!"/>
|
||||
<CardBoxComponentTitle title="Bienvenue sur votre application de Gestion Entrées Sorties"/>
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className='text-center text-gray-500'>This is a React.js/Node.js app generated by the <a className={`${textColor}`} href="https://flatlogic.com/generator">Flatlogic Web App Generator</a></p>
|
||||
<p className='text-center text-gray-500'>For guides and documentation please check
|
||||
your local README.md and the <a className={`${textColor}`} href="https://flatlogic.com/documentation">Flatlogic documentation</a></p>
|
||||
<div className="space-y-4 mb-6">
|
||||
<p className='text-center text-gray-500'>
|
||||
Suivez facilement les entrées et sorties de vos collaborateurs,
|
||||
gérez les badges provisoires et consultez les rapports d'heures en temps réel.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButtons className="flex flex-col space-y-3">
|
||||
<BaseButton
|
||||
href='/login'
|
||||
label='Login'
|
||||
color='info'
|
||||
href='/check-in'
|
||||
label='Pointage Entrée (Check-in)'
|
||||
color='success'
|
||||
icon={mdiClockIn}
|
||||
className='w-full'
|
||||
/>
|
||||
|
||||
<BaseButton
|
||||
href='/login'
|
||||
label='Accéder à l Administration'
|
||||
color='info'
|
||||
icon={mdiLogin}
|
||||
className='w-full'
|
||||
outline
|
||||
/>
|
||||
</BaseButtons>
|
||||
</CardBox>
|
||||
</div>
|
||||
@ -163,4 +170,3 @@ export default function Starter() {
|
||||
Starter.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutGuest>{page}</LayoutGuest>;
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
|
||||
import Head from 'next/head'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import CardBox from '../../components/CardBox'
|
||||
import LayoutAuthenticated from '../../layouts/Authenticated'
|
||||
@ -16,282 +14,69 @@ import FormField from '../../components/FormField'
|
||||
import BaseDivider from '../../components/BaseDivider'
|
||||
import BaseButtons from '../../components/BaseButtons'
|
||||
import BaseButton from '../../components/BaseButton'
|
||||
import FormCheckRadio from '../../components/FormCheckRadio'
|
||||
import FormCheckRadioGroup from '../../components/FormCheckRadioGroup'
|
||||
import FormFilePicker from '../../components/FormFilePicker'
|
||||
import FormImagePicker from '../../components/FormImagePicker'
|
||||
import { SelectField } from "../../components/SelectField";
|
||||
import { SelectFieldMany } from "../../components/SelectFieldMany";
|
||||
import { SwitchField } from '../../components/SwitchField'
|
||||
import {RichTextField} from "../../components/RichTextField";
|
||||
|
||||
import { update, fetch } from '../../stores/users/usersSlice'
|
||||
import { useAppDispatch, useAppSelector } from '../../stores/hooks'
|
||||
import { useRouter } from 'next/router'
|
||||
import {saveFile} from "../../helpers/fileSaver";
|
||||
import dataFormatter from '../../helpers/dataFormatter';
|
||||
import ImageField from "../../components/ImageField";
|
||||
|
||||
|
||||
|
||||
const EditUsersPage = () => {
|
||||
const router = useRouter()
|
||||
const dispatch = useAppDispatch()
|
||||
const initVals = {
|
||||
|
||||
|
||||
'firstName': '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'lastName': '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'phoneNumber': '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'email': '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
phoneNumber: '',
|
||||
email: '',
|
||||
disabled: false,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
avatar: [],
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
app_role: null,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
custom_permissions: [],
|
||||
|
||||
|
||||
|
||||
password: ''
|
||||
|
||||
password: '',
|
||||
matriculePaie: '',
|
||||
workdayId: '',
|
||||
productionSite: '',
|
||||
remoteWork: false,
|
||||
hiringDate: '',
|
||||
positionEntryDate: '',
|
||||
departureDate: '',
|
||||
service: '',
|
||||
position: '',
|
||||
team: '',
|
||||
departmentId: '',
|
||||
}
|
||||
const [initialValues, setInitialValues] = useState(initVals)
|
||||
|
||||
const { users } = useAppSelector((state) => state.users)
|
||||
|
||||
|
||||
const { id } = router.query
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetch({ id: id }))
|
||||
if (id) {
|
||||
dispatch(fetch({ id: id }))
|
||||
}
|
||||
}, [id])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof users === 'object') {
|
||||
setInitialValues(users)
|
||||
if (typeof users === 'object' && users !== null) {
|
||||
const newInitialVal = {...initVals};
|
||||
Object.keys(initVals).forEach(el => {
|
||||
if (users[el] !== undefined) {
|
||||
newInitialVal[el] = users[el]
|
||||
}
|
||||
})
|
||||
// Format dates for input type="date"
|
||||
if (newInitialVal.hiringDate) newInitialVal.hiringDate = newInitialVal.hiringDate.split('T')[0];
|
||||
if (newInitialVal.positionEntryDate) newInitialVal.positionEntryDate = newInitialVal.positionEntryDate.split('T')[0];
|
||||
if (newInitialVal.departureDate) newInitialVal.departureDate = newInitialVal.departureDate.split('T')[0];
|
||||
|
||||
setInitialValues(newInitialVal);
|
||||
}
|
||||
}, [users])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof users === 'object') {
|
||||
const newInitialVal = {...initVals};
|
||||
Object.keys(initVals).forEach(el => newInitialVal[el] = (users)[el])
|
||||
setInitialValues(newInitialVal);
|
||||
}
|
||||
}, [users])
|
||||
|
||||
const handleSubmit = async (data) => {
|
||||
await dispatch(update({ id: id, data }))
|
||||
await router.push('/users/users-list')
|
||||
@ -300,10 +85,10 @@ const EditUsersPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('Edit users')}</title>
|
||||
<title>{getPageTitle('Edit User')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit users'} main>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit User'} main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox>
|
||||
@ -313,358 +98,120 @@ const EditUsersPage = () => {
|
||||
onSubmit={(values) => handleSubmit(values)}
|
||||
>
|
||||
<Form>
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="First Name"
|
||||
>
|
||||
<Field
|
||||
name="firstName"
|
||||
placeholder="First Name"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="Last Name"
|
||||
>
|
||||
<Field
|
||||
name="lastName"
|
||||
placeholder="Last Name"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="Phone Number"
|
||||
>
|
||||
<Field
|
||||
name="phoneNumber"
|
||||
placeholder="Phone Number"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="E-Mail"
|
||||
>
|
||||
<Field
|
||||
name="email"
|
||||
placeholder="E-Mail"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='Disabled' labelFor='disabled'>
|
||||
<Field
|
||||
name='disabled'
|
||||
id='disabled'
|
||||
component={SwitchField}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField>
|
||||
<Field
|
||||
label='Avatar'
|
||||
color='info'
|
||||
icon={mdiUpload}
|
||||
path={'users/avatar'}
|
||||
name='avatar'
|
||||
id='avatar'
|
||||
schema={{
|
||||
size: undefined,
|
||||
formats: undefined,
|
||||
}}
|
||||
component={FormImagePicker}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='App Role' labelFor='app_role'>
|
||||
<Field
|
||||
name='app_role'
|
||||
id='app_role'
|
||||
component={SelectField}
|
||||
options={initialValues.app_role}
|
||||
itemRef={'roles'}
|
||||
|
||||
|
||||
|
||||
|
||||
showField={'name'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='Custom Permissions' labelFor='custom_permissions'>
|
||||
<Field
|
||||
name='custom_permissions'
|
||||
id='custom_permissions'
|
||||
component={SelectFieldMany}
|
||||
options={initialValues.custom_permissions}
|
||||
itemRef={'permissions'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
showField={'name'}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="Password"
|
||||
>
|
||||
<Field
|
||||
name="password"
|
||||
placeholder="password"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<FormField label="First Name">
|
||||
<Field name="firstName" placeholder="First Name" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Last Name">
|
||||
<Field name="lastName" placeholder="Last Name" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="E-Mail">
|
||||
<Field name="email" placeholder="E-Mail" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Phone Number">
|
||||
<Field name="phoneNumber" placeholder="Phone Number" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Matricule Paie">
|
||||
<Field name="matriculePaie" placeholder="Matricule Paie" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="WD ID">
|
||||
<Field name="workdayId" placeholder="WD ID" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Site de production">
|
||||
<Field name="productionSite" placeholder="Site de production" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Service">
|
||||
<Field name="service" placeholder="Service" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Poste">
|
||||
<Field name="position" placeholder="Poste" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Équipe (N+1)">
|
||||
<Field name="team" placeholder="Équipe (N+1)" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Département" labelFor="departmentId">
|
||||
<Field
|
||||
name="departmentId"
|
||||
id="departmentId"
|
||||
component={SelectField}
|
||||
options={initialValues.departmentId}
|
||||
itemRef={'departments'}
|
||||
showField={'name'}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date d'embauche">
|
||||
<Field name="hiringDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date d'entrée poste">
|
||||
<Field name="positionEntryDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date de départ">
|
||||
<Field name="departureDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label='Télétravail' labelFor='remoteWork'>
|
||||
<Field name='remoteWork' id='remoteWork' component={SwitchField}></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Disabled' labelFor='disabled'>
|
||||
<Field name='disabled' id='disabled' component={SwitchField}></Field>
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<FormField>
|
||||
<Field
|
||||
label='Avatar'
|
||||
color='info'
|
||||
icon={mdiUpload}
|
||||
path={'users/avatar'}
|
||||
name='avatar'
|
||||
id='avatar'
|
||||
schema={{
|
||||
size: undefined,
|
||||
formats: undefined,
|
||||
}}
|
||||
component={FormImagePicker}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='App Role' labelFor='app_role'>
|
||||
<Field
|
||||
name='app_role'
|
||||
id='app_role'
|
||||
component={SelectField}
|
||||
options={initialValues.app_role}
|
||||
itemRef={'roles'}
|
||||
showField={'name'}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Custom Permissions' labelFor='custom_permissions'>
|
||||
<Field
|
||||
name='custom_permissions'
|
||||
id='custom_permissions'
|
||||
component={SelectFieldMany}
|
||||
options={initialValues.custom_permissions}
|
||||
itemRef={'permissions'}
|
||||
showField={'name'}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Password">
|
||||
<Field name="password" type="password" placeholder="Leave blank to keep current" />
|
||||
</FormField>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseButtons>
|
||||
@ -683,13 +230,11 @@ const EditUsersPage = () => {
|
||||
EditUsersPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<LayoutAuthenticated
|
||||
|
||||
permission={'UPDATE_USERS'}
|
||||
|
||||
>
|
||||
{page}
|
||||
</LayoutAuthenticated>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditUsersPage
|
||||
export default EditUsersPage
|
||||
@ -28,135 +28,25 @@ import { useRouter } from 'next/router'
|
||||
import moment from 'moment';
|
||||
|
||||
const initialValues = {
|
||||
|
||||
|
||||
firstName: '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
lastName: '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
phoneNumber: '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
email: '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
disabled: false,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
avatar: [],
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
app_role: '',
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
custom_permissions: [],
|
||||
|
||||
|
||||
matriculePaie: '',
|
||||
workdayId: '',
|
||||
productionSite: '',
|
||||
remoteWork: false,
|
||||
hiringDate: '',
|
||||
positionEntryDate: '',
|
||||
departureDate: '',
|
||||
service: '',
|
||||
position: '',
|
||||
team: '',
|
||||
departmentId: '',
|
||||
}
|
||||
|
||||
|
||||
@ -164,9 +54,6 @@ const UsersNew = () => {
|
||||
const router = useRouter()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
|
||||
|
||||
|
||||
const handleSubmit = async (data) => {
|
||||
await dispatch(create(data))
|
||||
await router.push('/users/users-list')
|
||||
@ -174,220 +61,84 @@ const UsersNew = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('New Item')}</title>
|
||||
<title>{getPageTitle('New User')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New Item" main>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New User" main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox>
|
||||
<Formik
|
||||
initialValues={
|
||||
|
||||
initialValues
|
||||
|
||||
}
|
||||
initialValues={initialValues}
|
||||
onSubmit={(values) => handleSubmit(values)}
|
||||
>
|
||||
<Form>
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="First Name"
|
||||
>
|
||||
<Field
|
||||
name="firstName"
|
||||
placeholder="First Name"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="Last Name"
|
||||
>
|
||||
<Field
|
||||
name="lastName"
|
||||
placeholder="Last Name"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="Phone Number"
|
||||
>
|
||||
<Field
|
||||
name="phoneNumber"
|
||||
placeholder="Phone Number"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField
|
||||
label="E-Mail"
|
||||
>
|
||||
<Field
|
||||
name="email"
|
||||
placeholder="E-Mail"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='Disabled' labelFor='disabled'>
|
||||
<Field
|
||||
name='disabled'
|
||||
id='disabled'
|
||||
component={SwitchField}
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<FormField label="First Name">
|
||||
<Field name="firstName" placeholder="First Name" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Last Name">
|
||||
<Field name="lastName" placeholder="Last Name" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="E-Mail">
|
||||
<Field name="email" placeholder="E-Mail" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Phone Number">
|
||||
<Field name="phoneNumber" placeholder="Phone Number" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Matricule Paie">
|
||||
<Field name="matriculePaie" placeholder="Matricule Paie" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="WD ID">
|
||||
<Field name="workdayId" placeholder="WD ID" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Site de production">
|
||||
<Field name="productionSite" placeholder="Site de production" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Service">
|
||||
<Field name="service" placeholder="Service" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Poste">
|
||||
<Field name="position" placeholder="Poste" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Équipe (N+1)">
|
||||
<Field name="team" placeholder="Équipe (N+1)" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Département" labelFor="departmentId">
|
||||
<Field name="departmentId" id="departmentId" component={SelectField} options={[]} itemRef={'departments'}></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date d'embauche">
|
||||
<Field name="hiringDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date d'entrée poste">
|
||||
<Field name="positionEntryDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Date de départ">
|
||||
<Field name="departureDate" type="date" />
|
||||
</FormField>
|
||||
|
||||
<FormField label='Télétravail' labelFor='remoteWork'>
|
||||
<Field name='remoteWork' id='remoteWork' component={SwitchField}></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Disabled' labelFor='disabled'>
|
||||
<Field name='disabled' id='disabled' component={SwitchField}></Field>
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<FormField>
|
||||
<Field
|
||||
@ -405,60 +156,10 @@ const UsersNew = () => {
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label="App Role" labelFor="app_role">
|
||||
<Field name="app_role" id="app_role" component={SelectField} options={[]} itemRef={'roles'}></Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='Custom Permissions' labelFor='custom_permissions'>
|
||||
<Field
|
||||
name='custom_permissions'
|
||||
@ -469,10 +170,6 @@ const UsersNew = () => {
|
||||
</Field>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<BaseDivider />
|
||||
<BaseButtons>
|
||||
<BaseButton type="submit" color="info" label="Submit" />
|
||||
@ -490,13 +187,11 @@ const UsersNew = () => {
|
||||
UsersNew.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<LayoutAuthenticated
|
||||
|
||||
permission={'CREATE_USERS'}
|
||||
|
||||
>
|
||||
{page}
|
||||
</LayoutAuthenticated>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersNew
|
||||
export default UsersNew
|
||||
@ -1,12 +1,8 @@
|
||||
import React, { ReactElement, useEffect } from 'react';
|
||||
import Head from 'next/head'
|
||||
import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import dayjs from "dayjs";
|
||||
import {useAppDispatch, useAppSelector} from "../../stores/hooks";
|
||||
import {useRouter} from "next/router";
|
||||
import { fetch } from '../../stores/users/usersSlice'
|
||||
import {saveFile} from "../../helpers/fileSaver";
|
||||
import dataFormatter from '../../helpers/dataFormatter';
|
||||
import ImageField from "../../components/ImageField";
|
||||
import LayoutAuthenticated from "../../layouts/Authenticated";
|
||||
@ -25,27 +21,21 @@ const UsersView = () => {
|
||||
const router = useRouter()
|
||||
const dispatch = useAppDispatch()
|
||||
const { users } = useAppSelector((state) => state.users)
|
||||
|
||||
|
||||
const { id } = router.query;
|
||||
|
||||
function removeLastCharacter(str) {
|
||||
console.log(str,`str`)
|
||||
return str.slice(0, -1);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetch({ id }));
|
||||
if (id) {
|
||||
dispatch(fetch({ id }));
|
||||
}
|
||||
}, [dispatch, id]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('View users')}</title>
|
||||
<title>{getPageTitle('View User')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={removeLastCharacter('View users')} main>
|
||||
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'View User'} main>
|
||||
<BaseButton
|
||||
color='info'
|
||||
label='Edit'
|
||||
@ -53,153 +43,85 @@ const UsersView = () => {
|
||||
/>
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox>
|
||||
|
||||
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>First Name</p>
|
||||
<p>{users?.firstName}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Last Name</p>
|
||||
<p>{users?.lastName}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Phone Number</p>
|
||||
<p>{users?.phoneNumber}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>E-Mail</p>
|
||||
<p>{users?.email}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Phone Number</p>
|
||||
<p>{users?.phoneNumber}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Matricule Paie</p>
|
||||
<p>{users?.matriculePaie}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>WD ID</p>
|
||||
<p>{users?.workdayId}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Site de production</p>
|
||||
<p>{users?.productionSite}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Service</p>
|
||||
<p>{users?.service}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Poste</p>
|
||||
<p>{users?.position}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Équipe (N+1)</p>
|
||||
<p>{users?.team}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Département</p>
|
||||
<p>{users?.department?.name ?? 'No data'}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Date d'embauche</p>
|
||||
<p>{dataFormatter.dateFormatter(users?.hiringDate)}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Date d'entrée poste</p>
|
||||
<p>{dataFormatter.dateFormatter(users?.positionEntryDate)}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Date de départ</p>
|
||||
<p>{dataFormatter.dateFormatter(users?.departureDate)}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<FormField label='Télétravail'>
|
||||
<SwitchField
|
||||
field={{name: 'remoteWork', value: users?.remoteWork}}
|
||||
form={{setFieldValue: () => null}}
|
||||
disabled
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<FormField label='Disabled'>
|
||||
<SwitchField
|
||||
field={{name: 'disabled', value: users?.disabled}}
|
||||
@ -207,40 +129,8 @@ const UsersView = () => {
|
||||
disabled
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Avatar</p>
|
||||
{users?.avatar?.length
|
||||
@ -253,83 +143,13 @@ const UsersView = () => {
|
||||
) : <p>No Avatar</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>App Role</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>{users?.app_role?.name ?? 'No data'}</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<p>{users?.app_role?.name ?? 'No data'}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<>
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Custom Permissions</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
@ -339,42 +159,16 @@ const UsersView = () => {
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.custom_permissions && Array.isArray(users.custom_permissions) &&
|
||||
users.custom_permissions.map((item: any) => (
|
||||
<tr key={item.id} onClick={() => router.push(`/permissions/permissions-view/?id=${item.id}`)}>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td data-label="name">
|
||||
{ item.name }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@ -382,310 +176,7 @@ const UsersView = () => {
|
||||
</div>
|
||||
{!users?.custom_permissions?.length && <div className={'text-center py-4'}>No data</div>}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Departments Manager</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Nom</th>
|
||||
|
||||
|
||||
|
||||
<th>Code</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Localisation</th>
|
||||
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.departments_manager && Array.isArray(users.departments_manager) &&
|
||||
users.departments_manager.map((item: any) => (
|
||||
<tr key={item.id} onClick={() => router.push(`/departments/departments-view/?id=${item.id}`)}>
|
||||
|
||||
|
||||
<td data-label="name">
|
||||
{ item.name }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="code">
|
||||
{ item.code }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td data-label="location">
|
||||
{ item.location }
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!users?.departments_manager?.length && <div className={'text-center py-4'}>No data</div>}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Time_entries Collaborateur</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Heureentrée</th>
|
||||
|
||||
|
||||
|
||||
<th>Heuresortie</th>
|
||||
|
||||
|
||||
|
||||
<th>Numérobadgeprovisoire</th>
|
||||
|
||||
|
||||
|
||||
<th>Statut</th>
|
||||
|
||||
|
||||
|
||||
<th>Résumé</th>
|
||||
|
||||
|
||||
|
||||
<th>Note</th>
|
||||
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.time_entries_employee && Array.isArray(users.time_entries_employee) &&
|
||||
users.time_entries_employee.map((item: any) => (
|
||||
<tr key={item.id} onClick={() => router.push(`/time_entries/time_entries-view/?id=${item.id}`)}>
|
||||
|
||||
|
||||
|
||||
|
||||
<td data-label="start_time">
|
||||
{ dataFormatter.dateTimeFormatter(item.start_time) }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="end_time">
|
||||
{ dataFormatter.dateTimeFormatter(item.end_time) }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="badge_number">
|
||||
{ item.badge_number }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="status">
|
||||
{ item.status }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="summary">
|
||||
{ item.summary }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="note">
|
||||
{ item.note }
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!users?.time_entries_employee?.length && <div className={'text-center py-4'}>No data</div>}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Import_jobs Importépar</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Nomfichier</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Dateimport</th>
|
||||
|
||||
|
||||
|
||||
<th>Statutimport</th>
|
||||
|
||||
|
||||
|
||||
<th>Lignestraitées</th>
|
||||
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.import_jobs_imported_by && Array.isArray(users.import_jobs_imported_by) &&
|
||||
users.import_jobs_imported_by.map((item: any) => (
|
||||
<tr key={item.id} onClick={() => router.push(`/import_jobs/import_jobs-view/?id=${item.id}`)}>
|
||||
|
||||
|
||||
<td data-label="filename">
|
||||
{ item.filename }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td data-label="imported_at">
|
||||
{ dataFormatter.dateTimeFormatter(item.imported_at) }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="status">
|
||||
{ item.status }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="rows_processed">
|
||||
{ item.rows_processed }
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!users?.import_jobs_imported_by?.length && <div className={'text-center py-4'}>No data</div>}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Badges Affectéà</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Numérobadge</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Dateémission</th>
|
||||
|
||||
|
||||
|
||||
<th>Restitué</th>
|
||||
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.badges_assigned_to && Array.isArray(users.badges_assigned_to) &&
|
||||
users.badges_assigned_to.map((item: any) => (
|
||||
<tr key={item.id} onClick={() => router.push(`/badges/badges-view/?id=${item.id}`)}>
|
||||
|
||||
|
||||
<td data-label="number">
|
||||
{ item.number }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td data-label="issued_at">
|
||||
{ dataFormatter.dateTimeFormatter(item.issued_at) }
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td data-label="returned">
|
||||
{ dataFormatter.booleanFormatter(item.returned) }
|
||||
</td>
|
||||
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!users?.badges_assigned_to?.length && <div className={'text-center py-4'}>No data</div>}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<BaseDivider />
|
||||
|
||||
@ -703,9 +194,7 @@ const UsersView = () => {
|
||||
UsersView.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<LayoutAuthenticated
|
||||
|
||||
permission={'READ_USERS'}
|
||||
|
||||
>
|
||||
{page}
|
||||
</LayoutAuthenticated>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user