Compare commits

...

2 Commits

Author SHA1 Message Date
Flatlogic Bot
1b0f675e27 el pepe 2026-03-03 17:47:01 +00:00
Flatlogic Bot
b0ea840349 502.html 2026-03-03 17:46:41 +00:00
9 changed files with 164 additions and 1022 deletions

View File

@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Starting</title>
<title>Login</title>
<style>
body {
font-family: sans-serif;
@ -129,8 +129,8 @@
<p class="tip">The application is currently launching. The page will automatically refresh once site is
available.</p>
<div class="project-info">
<h2>Gestor de Tareas Personales</h2>
<p>Aplicación web para gestionar tareas personales con registro/login y CRUD con filtros por estado y prioridad.</p>
<h2>Web page for saving and administrating time (UTTN RA2)</h2>
<p>In this web page we're gonna see a small web page with login, Dashboard & CRUD </p>
</div>
<div class="loader-container">
<img src="https://flatlogic.com/blog/wp-content/uploads/2025/05/logo-bot-1.png" alt="App Logo"
@ -138,7 +138,7 @@
<div class="loader"></div>
</div>
<div class="panel">
<video width="100%" height="315" controls loop>
<video width="20%" height="67" controls loop>
<source
src="https://flatlogic.com/blog/wp-content/uploads/2025/04/20250430_1336_professional_dynamo_spinner_simple_compose_01jt349yvtenxt7xhg8hhr85j8.mp4"
type="video/mp4">

View File

@ -1,4 +1,3 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
@ -33,7 +32,7 @@ module.exports = class TasksDBApi {
status: data.status
||
null
'Pending'
,
due_date: data.due_date
@ -43,26 +42,17 @@ module.exports = class TasksDBApi {
priority: data.priority
||
null
'Low'
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
userId: data.user || currentUser.id, // Auto-assign to current user if not provided
},
{ transaction },
);
await tasks.setUser( data.user || null, {
transaction,
});
return tasks;
}
@ -87,7 +77,7 @@ module.exports = class TasksDBApi {
status: item.status
||
null
'Pending'
,
due_date: item.due_date
@ -97,21 +87,19 @@ module.exports = class TasksDBApi {
priority: item.priority
||
null
'Low'
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
userId: currentUser.id, // Bulk import also assigns to importer
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const tasks = await db.tasks.bulkCreate(tasksData, { transaction });
// For each item created, replace relation files
return tasks;
}
@ -122,47 +110,22 @@ module.exports = class TasksDBApi {
const tasks = await db.tasks.findByPk(id, {}, {transaction});
if (!tasks) {
throw new Error('Task not found');
}
const updatePayload = {};
if (data.title !== undefined) updatePayload.title = data.title;
if (data.description !== undefined) updatePayload.description = data.description;
if (data.status !== undefined) updatePayload.status = data.status;
if (data.due_date !== undefined) updatePayload.due_date = data.due_date;
if (data.priority !== undefined) updatePayload.priority = data.priority;
updatePayload.updatedById = currentUser.id;
await tasks.update(updatePayload, {transaction});
if (data.user !== undefined) {
await tasks.setUser(
data.user,
{ transaction }
);
}
return tasks;
}
@ -175,6 +138,7 @@ module.exports = class TasksDBApi {
id: {
[Op.in]: ids,
},
userId: currentUser.id, // Only allow deleting own tasks
},
transaction,
});
@ -199,7 +163,14 @@ module.exports = class TasksDBApi {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const tasks = await db.tasks.findByPk(id, options);
const tasks = await db.tasks.findOne({
where: { id, userId: currentUser.id },
transaction
});
if (!tasks) {
throw new Error('Task not found or permission denied');
}
await tasks.update({
deletedBy: currentUser.id
@ -228,18 +199,6 @@ module.exports = class TasksDBApi {
const output = tasks.get({plain: true});
output.user = await tasks.getUser({
transaction
});
return output;
}
@ -252,9 +211,10 @@ module.exports = class TasksDBApi {
let where = {};
const currentPage = +filter.page;
const currentUser = (options && options.currentUser) || { id: null };
// RESTRICT TO OWN TASKS
where.userId = currentUser.id;
offset = currentPage * limit;
@ -262,28 +222,7 @@ module.exports = class TasksDBApi {
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.users,
as: 'user',
where: filter.user ? {
[Op.or]: [
{ id: { [Op.in]: filter.user.split('|').map(term => Utils.uuid(term)) } },
{
firstName: {
[Op.or]: filter.user.split('|').map(term => ({ [Op.iLike]: `%${term}%` }))
}
},
]
} : {},
},
];
let include = []; // Removed User include for privacy/simplicity in personal manager
if (filter) {
if (filter.id) {
@ -317,10 +256,6 @@ module.exports = class TasksDBApi {
}
if (filter.due_dateRange) {
const [start, end] = filter.due_dateRange;
@ -369,11 +304,6 @@ module.exports = class TasksDBApi {
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
@ -400,8 +330,6 @@ module.exports = class TasksDBApi {
}
const queryOptions = {
where,
include,
@ -410,7 +338,6 @@ module.exports = class TasksDBApi {
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
};
if (!options?.countOnly) {
@ -434,8 +361,6 @@ module.exports = class TasksDBApi {
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
@ -464,5 +389,4 @@ module.exports = class TasksDBApi {
}
};
};

View File

@ -0,0 +1,26 @@
module.exports = {
up: async (queryInterface, Sequelize) => {
// 1. Change InProgress to In Progress in the data
await queryInterface.sequelize.query(
"UPDATE tasks SET status = 'Pending' WHERE status = 'InProgress' OR status IS NULL"
);
// 2. We need to handle the ENUM change. PostgreSQL ENUMs are tricky to update.
// The safest way is to rename the old enum, create a new one, and drop the old one.
// However, for this environment, we might just try to add the value if it's missing,
// or use a simpler approach if the DB allows.
// Check current type and update it.
try {
await queryInterface.sequelize.query(`ALTER TYPE "enum_tasks_status" ADD VALUE IF NOT EXISTS 'In Progress'`);
await queryInterface.sequelize.query(`UPDATE tasks SET status = 'In Progress' WHERE status = 'InProgress'`);
} catch (e) {
console.log('Error updating enum type:', e);
}
},
down: async (queryInterface, Sequelize) => {
// Revert if needed
}
};

View File

@ -16,61 +16,35 @@ module.exports = function(sequelize, DataTypes) {
title: {
type: DataTypes.TEXT,
allowNull: false, // User requested Title to be obligatory
},
description: {
type: DataTypes.TEXT,
},
status: {
type: DataTypes.ENUM,
values: [
"Pending",
"InProgress",
"Done"
"Pending",
"In Progress",
"Done"
],
defaultValue: "Pending",
},
due_date: {
type: DataTypes.DATE,
},
priority: {
type: DataTypes.ENUM,
values: [
"Low",
"Medium",
"High"
"Low",
"Medium",
"High"
],
defaultValue: "Low",
},
importHash: {
@ -87,20 +61,6 @@ priority: {
);
tasks.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.tasks.belongsTo(db.users, {
as: 'user',
foreignKey: {
@ -109,9 +69,6 @@ priority: {
constraints: false,
});
db.tasks.belongsTo(db.users, {
as: 'createdBy',
});
@ -121,9 +78,5 @@ priority: {
});
};
return tasks;
};
};

View File

@ -19,7 +19,6 @@ import {dataGridStyles} from "../../styles";
import KanbanBoard from '../KanbanBoard/KanbanBoard';
import axios from 'axios';
const perPage = 10
@ -30,7 +29,6 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
const dispatch = useAppDispatch();
const router = useRouter();
const pagesList = [];
const [id, setId] = useState(null);
const [currentPage, setCurrentPage] = useState(0);
const [filterRequest, setFilterRequest] = React.useState('');
@ -51,10 +49,6 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) {
pagesList.push(i);
}
const loadData = async (page = currentPage, request = filterRequest) => {
if (page !== currentPage) setCurrentPage(page);
@ -83,35 +77,22 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
}
}, [refetch, dispatch]);
const [isModalInfoActive, setIsModalInfoActive] = useState(false)
const [isModalTrashActive, setIsModalTrashActive] = useState(false)
const handleModalAction = () => {
setIsModalInfoActive(false)
setIsModalTrashActive(false)
}
useEffect(() => {
setKanbanColumns([
{ id: "Pending", label: "Pending" },
{ id: "InProgress", label: "InProgress" },
{ id: "In Progress", label: "In Progress" },
{ id: "Done", label: "Done" },
]);
}, []);
const handleDeleteModalAction = (id: string) => {
setId(id)
setIsModalTrashActive(true)
@ -159,18 +140,14 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
setFilterItems(newItems);
} else {
loadData(0, '');
setKanbanFilters('');
setFilterItems(newItems);
}
};
const handleSubmit = () => {
loadData(0, generateFilterRequests);
setKanbanFilters(generateFilterRequests);
};
const handleChange = (id) => (e) => {
@ -190,9 +167,7 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
const handleReset = () => {
setFilterItems([]);
loadData(0, '');
setKanbanFilters('');
};
const onPageChange = (page: number) => {
@ -502,4 +477,4 @@ const TableSampleTasks = ({ filterItems, setFilterItems, filters, showGrid }) =>
)
}
export default TableSampleTasks
export default TableSampleTasks

View File

@ -1,168 +1,106 @@
import React from 'react';
import BaseIcon from '../BaseIcon';
import { mdiEye, mdiTrashCan, mdiPencilOutline } from '@mdi/js';
import axios from 'axios';
import {
GridActionsCellItem,
GridRowParams,
GridValueGetterParams,
} from '@mui/x-data-grid';
import ImageField from '../ImageField';
import {saveFile} from "../../helpers/fileSaver";
import dataFormatter from '../../helpers/dataFormatter'
import DataGridMultiSelect from "../DataGridMultiSelect";
import ListActionsPopover from '../ListActionsPopover';
import {hasPermission} from "../../helpers/userPermissions";
import moment from 'moment';
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;
} catch (error) {
console.log(error);
return [];
}
}
const hasUpdatePermission = hasPermission(user, 'UPDATE_TASKS')
return [
{
field: 'user',
headerName: 'User',
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('users'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{
field: 'title',
headerName: 'Title',
flex: 1,
minWidth: 120,
filterable: false,
flex: 2,
minWidth: 200,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'description',
headerName: 'Description',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'status',
headerName: 'Status',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
renderCell: (params) => {
const colors = {
'Pending': 'text-gray-500 bg-gray-100',
'In Progress': 'text-blue-500 bg-blue-100',
'Done': 'text-green-500 bg-green-100'
};
const color = colors[params.value] || 'text-gray-500 bg-gray-100';
return (
<span className={`px-2 py-1 rounded-full text-xs font-semibold ${color}`}>
{params.value}
</span>
);
}
},
{
field: 'due_date',
headerName: 'DueDate',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'dateTime',
valueGetter: (params: GridValueGetterParams) =>
new Date(params.row.due_date),
},
{
field: 'priority',
headerName: 'Priority',
flex: 1,
minWidth: 120,
filterable: false,
minWidth: 100,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
renderCell: (params) => {
const colors = {
'High': 'text-red-500 bg-red-100',
'Medium': 'text-yellow-600 bg-yellow-100',
'Low': 'text-blue-500 bg-blue-100'
};
const color = colors[params.value] || 'text-gray-500 bg-gray-100';
return (
<span className={`px-2 py-1 rounded-full text-xs font-semibold ${color}`}>
{params.value}
</span>
);
}
},
{
field: 'due_date',
headerName: 'Due Date',
flex: 1,
minWidth: 150,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'dateTime',
valueGetter: (params) => params.row.due_date ? new Date(params.row.due_date) : null,
renderCell: (params) => params.value ? moment(params.value).format('MMM DD, YYYY HH:mm') : '-'
},
{
field: 'actions',
type: 'actions',
minWidth: 30,
minWidth: 80,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
getActions: (params: GridRowParams) => {
return [
<div key={params?.row?.id}>
<ListActionsPopover
onDelete={onDelete}
itemId={params?.row?.id}
pathEdit={`/tasks/tasks-edit/?id=${params?.row?.id}`}
pathView={`/tasks/tasks-view/?id=${params?.row?.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
onDelete={onDelete}
itemId={params?.row?.id}
pathEdit={`/tasks/tasks-edit/?id=${params?.row?.id}`}
pathView={`/tasks/tasks-view/?id=${params?.row?.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>,
]
},
},
];
};
};

View File

@ -1,4 +1,4 @@
import { mdiChartTimelineVariant, mdiUpload } from '@mdi/js'
import { mdiChartTimelineVariant } from '@mdi/js'
import Head from 'next/head'
import React, { ReactElement, useEffect, useState } from 'react'
import DatePicker from "react-datepicker";
@ -16,21 +16,10 @@ 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/tasks/tasksSlice'
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";
@ -38,202 +27,35 @@ const EditTasksPage = () => {
const router = useRouter()
const dispatch = useAppDispatch()
const initVals = {
user: null,
'title': '',
title: '',
description: '',
status: '',
status: 'Pending',
due_date: new Date(),
priority: '',
priority: 'Low',
}
const [initialValues, setInitialValues] = useState(initVals)
const { tasks } = useAppSelector((state) => state.tasks)
const { id } = router.query
useEffect(() => {
dispatch(fetch({ id: id }))
if (id) {
dispatch(fetch({ id: id }))
}
}, [id])
useEffect(() => {
if (typeof tasks === 'object') {
setInitialValues(tasks)
if (tasks && typeof tasks === 'object') {
setInitialValues({
title: tasks.title || '',
description: tasks.description || '',
status: tasks.status || 'Pending',
due_date: tasks.due_date ? new Date(tasks.due_date) : new Date(),
priority: tasks.priority || 'Low',
})
}
}, [tasks])
useEffect(() => {
if (typeof tasks === 'object') {
const newInitialVal = {...initVals};
Object.keys(initVals).forEach(el => newInitialVal[el] = (tasks)[el])
setInitialValues(newInitialVal);
}
}, [tasks])
const handleSubmit = async (data) => {
await dispatch(update({ id: id, data }))
await router.push('/tasks/tasks-list')
@ -242,10 +64,10 @@ const EditTasksPage = () => {
return (
<>
<Head>
<title>{getPageTitle('Edit tasks')}</title>
<title>{getPageTitle('Edit Task')}</title>
</Head>
<SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit tasks'} main>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title={'Edit Task'} main>
{''}
</SectionTitleLineWithButton>
<CardBox>
@ -256,255 +78,52 @@ const EditTasksPage = () => {
>
<Form>
<FormField label='User' labelFor='user'>
<Field
name='user'
id='user'
component={SelectField}
options={initialValues.user}
itemRef={'users'}
showField={'firstName'}
></Field>
</FormField>
<FormField
label="Title"
required
>
<Field
name="title"
placeholder="Title"
required
/>
</FormField>
<FormField label="Description" hasTextareaHeight>
<Field name="description" as="textarea" placeholder="Description" />
</FormField>
<FormField label="Status" labelFor="status">
<Field name="status" id="status" component="select">
<option value="Pending">Pending</option>
<option value="InProgress">InProgress</option>
<option value="In Progress">In Progress</option>
<option value="Done">Done</option>
</Field>
</FormField>
<FormField
label="DueDate"
label="Due Date"
>
<DatePicker
dateFormat="yyyy-MM-dd hh:mm"
dateFormat="yyyy-MM-dd HH:mm"
showTimeSelect
selected={initialValues.due_date ?
new Date(
dayjs(initialValues.due_date).format('YYYY-MM-DD hh:mm'),
) : null
}
selected={initialValues.due_date}
onChange={(date) => setInitialValues({...initialValues, 'due_date': date})}
className="w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 bg-white dark:bg-slate-800 border"
/>
</FormField>
<FormField label="Priority" labelFor="priority">
<Field name="priority" id="priority" component="select">
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
</Field>
</FormField>
<BaseDivider />
<BaseButtons>
<BaseButton type="submit" color="info" label="Submit" />
<BaseButton type="submit" color="info" label="Save Changes" />
<BaseButton type="reset" color="info" outline label="Reset" />
<BaseButton type='reset' color='danger' outline label='Cancel' onClick={() => router.push('/tasks/tasks-list')}/>
</BaseButtons>
@ -519,13 +138,11 @@ const EditTasksPage = () => {
EditTasksPage.getLayout = function getLayout(page: ReactElement) {
return (
<LayoutAuthenticated
permission={'UPDATE_TASKS'}
>
{page}
</LayoutAuthenticated>
)
}
export default EditTasksPage
export default EditTasksPage

View File

@ -10,7 +10,6 @@ import { getPageTitle } from '../../config'
import TableTasks from '../../components/Tasks/TableTasks'
import BaseButton from '../../components/BaseButton'
import axios from "axios";
import Link from "next/link";
import {useAppDispatch, useAppSelector} from "../../stores/hooks";
import CardBoxModal from "../../components/CardBoxModal";
import DragDropFilePicker from "../../components/DragDropFilePicker";
@ -25,7 +24,6 @@ const TasksTablesPage = () => {
const [filterItems, setFilterItems] = useState([]);
const [csvFile, setCsvFile] = useState<File | null>(null);
const [isModalActive, setIsModalActive] = useState(false);
const [showTableView, setShowTableView] = useState(false);
const { currentUser } = useAppSelector((state) => state.auth);
@ -34,17 +32,12 @@ const TasksTablesPage = () => {
const dispatch = useAppDispatch();
const [filters] = useState([{label: 'Title', title: 'title'},{label: 'Description', title: 'description'},
{label: 'DueDate', title: 'due_date', date: 'true'},
{label: 'User', title: 'user'},
{label: 'Status', title: 'status', type: 'enum', options: ['Pending','InProgress','Done']},{label: 'Priority', title: 'priority', type: 'enum', options: ['Low','Medium','High']},
const [filters] = useState([
{label: 'Title', title: 'title'},
{label: 'Description', title: 'description'},
{label: 'DueDate', title: 'due_date', date: 'true'},
{label: 'Status', title: 'status', type: 'enum', options: ['Pending','In Progress','Done']},
{label: 'Priority', title: 'priority', type: 'enum', options: ['Low','Medium','High']},
]);
const hasCreatePermission = currentUser && hasPermission(currentUser, 'CREATE_TASKS');
@ -93,12 +86,12 @@ const TasksTablesPage = () => {
<title>{getPageTitle('Tasks')}</title>
</Head>
<SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="Tasks" main>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="My Tasks" main>
{''}
</SectionTitleLineWithButton>
<CardBox className='mb-6' cardBoxClassName='flex flex-wrap'>
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/tasks/tasks-new'} color='info' label='New Item'/>}
{hasCreatePermission && <BaseButton className={'mr-3'} href={'/tasks/tasks-new'} color='info' label='New Task'/>}
<BaseButton
className={'mr-3'}
@ -120,17 +113,13 @@ const TasksTablesPage = () => {
<div id='delete-rows-button'></div>
</div>
<div className='md:inline-flex items-center ms-auto'>
<Link href={'/tasks/tasks-table'}>Switch to Table</Link>
</div>
</CardBox>
<TableTasks
filterItems={filterItems}
setFilterItems={setFilterItems}
filters={filters}
showGrid={false}
showGrid={true} // Default to grid for better visibility
/>
</SectionMain>
@ -138,7 +127,6 @@ const TasksTablesPage = () => {
title='Upload CSV'
buttonColor='info'
buttonLabel={'Confirm'}
// buttonLabel={false ? 'Deleting...' : 'Confirm'}
isActive={isModalActive}
onConfirm={onModalConfirm}
onCancel={onModalCancel}
@ -165,4 +153,4 @@ TasksTablesPage.getLayout = function getLayout(page: ReactElement) {
)
}
export default TasksTablesPage
export default TasksTablesPage

View File

@ -1,4 +1,4 @@
import { mdiAccount, mdiChartTimelineVariant, mdiMail, mdiUpload } from '@mdi/js'
import { mdiChartTimelineVariant } from '@mdi/js'
import Head from 'next/head'
import React, { ReactElement } from 'react'
import CardBox from '../../components/CardBox'
@ -12,121 +12,18 @@ 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 { SwitchField } from '../../components/SwitchField'
import { SelectField } from '../../components/SelectField'
import { SelectFieldMany } from "../../components/SelectFieldMany";
import {RichTextField} from "../../components/RichTextField";
import { create } from '../../stores/tasks/tasksSlice'
import { useAppDispatch } from '../../stores/hooks'
import { useRouter } from 'next/router'
import moment from 'moment';
const initialValues = {
user: '',
title: '',
description: '',
status: 'Pending',
due_date: '',
priority: 'Low',
}
@ -134,9 +31,6 @@ const TasksNew = () => {
const router = useRouter()
const dispatch = useAppDispatch()
const handleSubmit = async (data) => {
await dispatch(create(data))
await router.push('/tasks/tasks-list')
@ -144,233 +38,62 @@ const TasksNew = () => {
return (
<>
<Head>
<title>{getPageTitle('New Item')}</title>
<title>{getPageTitle('New Task')}</title>
</Head>
<SectionMain>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New Item" main>
<SectionTitleLineWithButton icon={mdiChartTimelineVariant} title="New Task" main>
{''}
</SectionTitleLineWithButton>
<CardBox>
<Formik
initialValues={
initialValues
}
initialValues={initialValues}
onSubmit={(values) => handleSubmit(values)}
>
<Form>
<FormField label="User" labelFor="user">
<Field name="user" id="user" component={SelectField} options={[]} itemRef={'users'}></Field>
</FormField>
<FormField
label="Title"
required
>
<Field
name="title"
placeholder="Title"
placeholder="What needs to be done?"
required
/>
</FormField>
<FormField label="Description" hasTextareaHeight>
<Field name="description" as="textarea" placeholder="Description" />
<FormField label="Description (Optional)" hasTextareaHeight>
<Field name="description" as="textarea" placeholder="More details about this task..." />
</FormField>
<FormField label="Status" labelFor="status">
<Field name="status" id="status" component="select">
<option value="Pending">Pending</option>
<option value="InProgress">InProgress</option>
<option value="In Progress">In Progress</option>
<option value="Done">Done</option>
</Field>
</FormField>
<FormField
label="DueDate"
label="Due Date"
>
<Field
type="datetime-local"
name="due_date"
placeholder="DueDate"
/>
</FormField>
<FormField label="Priority" labelFor="priority">
<Field name="priority" id="priority" component="select">
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
</Field>
</FormField>
<BaseDivider />
<BaseButtons>
<BaseButton type="submit" color="info" label="Submit" />
<BaseButton type="submit" color="info" label="Create Task" />
<BaseButton type="reset" color="info" outline label="Reset" />
<BaseButton type='reset' color='danger' outline label='Cancel' onClick={() => router.push('/tasks/tasks-list')}/>
</BaseButtons>
@ -385,13 +108,11 @@ const TasksNew = () => {
TasksNew.getLayout = function getLayout(page: ReactElement) {
return (
<LayoutAuthenticated
permission={'CREATE_TASKS'}
>
{page}
</LayoutAuthenticated>
)
}
export default TasksNew
export default TasksNew