Compare commits

...

40 Commits

Author SHA1 Message Date
Oksana Stepanenko 61012fdc41 FIX | Fix logout on contact details page, fix handle stop session 2 years ago
Oksana Stepanenko a66f1707dc FIX | Fix phone numbers/email/login validation on create/update user 2 years ago
Oksana Stepanenko e674469e49 MERGE | Merge with stage 2 years ago
Oksana Stepanenko f156b8d277 FIX | Fix page autoreload on refresh token 2 years ago
Oksana Stepanenko 42637af165 CHANGE | Show user with first, middle and last name (except chats page) 2 years ago
Oksana Stepanenko 91c276c4c0 FIX | Fix task comment menu open logig, fix check user permissions for task 2 years ago
Oksana Stepanenko 80490dffee FIX | Unselect chat on logout, prevent user can open chat details of deleted chat 2 years ago
Oksana Stepanenko e7ed0452b6 FIX | Fix overflow file long name on chat messages page and file preview modal 2 years ago
Oksana Stepanenko 0d8eccad13 CHANGE | Change count tasks component behavior on user profile page 2 years ago
Oksana Stepanenko 7719cddb78 FIX | Add right sorting in factories, group permissions, ips and taxonomies lists 2 years ago
Oksana Stepanenko 883d80dc27 CHANGE | Change user date of birth field validation 2 years ago
Oksana Stepanenko fdb3686aca FIX | Taxonomy page: add data order, fix loader 2 years ago
Oksana Stepanenko 100bdcc440 FIX | Reset sidebar filters on logout 2 years ago
Oksana Stepanenko 46525d2dce FIX | Prevent some warnings/errors in console 2 years ago
Oksana Stepanenko e002ddeb8b FIX | Use table row number from saved settings 2 years ago
Oksana Stepanenko 3046b128a5 FIX | Handle errors on delete users, show error notification 2 years ago
Oksana Stepanenko 7e79449210 FIX | Fix validation on create/updte user 2 years ago
Oksana Stepanenko ce1eed8851 CHANGE | Add default sorting by user name in contacts and users tables 2 years ago
Oksana Stepanenko 5fcfcfa96d FIX | Fix edit task comments modal 2 years ago
Oksana Stepanenko 3bae8984c2 FIX | Limit available dates in finish tasks modal 2 years ago
Oksana Stepanenko 5392ac6b7b FIX | Fix create/update task modal, add new-task socket signal handler, fix print task 2 years ago
Oksana Stepanenko 4af728a2eb FIX | Factories page view and action according to user permissions 2 years ago
Oksana Stepanenko 2be86b8106 FIX | Add default avatar in chat user info modal, fix permitted action on taxonomy page 2 years ago
Oksana Stepanenko 8932525f66 FIX | Update message in pinned block after edit message 2 years ago
Oksana Stepanenko 99813c5b34 FIX | Fix mentions 2 years ago
Oksana Stepanenko 65ede38a5f Merge branch 'fix/bugs-fix' of https://gitlab.com/jetup/rws/rws-web-app into fix/bugs-fix 2 years ago
Oksana Stepanenko 8f7557a2ff FIX | Prevent open context menu for several chat messages at the same time 2 years ago
Oksana Stepanenko b32d78d45a FEATURE | Reply to message with photo/video/file message 2 years ago
Oksana Stepanenko bcb723db74 FIX | Fix: delete chat, chat settings modal styles, select chat users list, smiles block styles 2 years ago
Oksana Stepanenko 0a7f92b17a FIX | Fix show tasks statistics on user details page 2 years ago
Oksana Stepanenko 8abf3a870d CHANGE | Redirect to contact details page when press today birthday notification details button 2 years ago
Oksana Stepanenko 18cd7b7313 STYLE | Align column header and content to the left 2 years ago
Oksana Stepanenko ec9b91fed1 CHANGE | Tasks table: highlight selected rows, rows with opened task 2 years ago
Oksana Stepanenko 94e46b2e89 FIX | Update task modal: fix render task data when reopen it for update, fix selectable fields clearing 2 years ago
Oksana Stepanenko 2bda4390ef CHANGE | Select user on create/update task form: sort users in list, current user on top of list 2 years ago
Oksana Stepanenko deca8d5e4e CHORE | Add icons to taxonomies submenu items in sidebar menu 2 years ago
Oksana Stepanenko 1f364ea36a CHANGE | Change popover styles in tasks table 2 years ago
Oksana Stepanenko 3a8eaa0f3d CHORE | Disable duplicate email and login fields on user profile page 2 years ago
Oksana Stepanenko 8340496578 FIX | Fix redirect to tasks page after login (redirect to '/' after logout) 2 years ago
Oksana Stepanenko 9bf40ebd54 FIX | Fix outdate tasks rendering, change some antd components colors to main app color 2 years ago
  1. 2
      src/api/contacts/requests.ts
  2. 1
      src/api/tasks-comments/responses.interfaces.ts
  3. 1
      src/api/tasks/responses.interfaces.ts
  4. 6
      src/api/tasks/transform.ts
  5. 2
      src/api/users/requests.ts
  6. 23
      src/components/Forms/PhoneNumberController/index.tsx
  7. 9
      src/components/Modal/index.tsx
  8. 23
      src/components/SmartComponents/UserSelectWithSearch.tsx
  9. 57
      src/containers/Chats/hooks/use-chats-list.hook.ts
  10. 22
      src/containers/Chats/modals/user-info.modal.tsx
  11. 13
      src/containers/Chats/plugins/chat-item.component.tsx
  12. 4
      src/containers/Chats/plugins/style.scss
  13. 11
      src/containers/Contact/components/contact-main.component.tsx
  14. 4
      src/containers/Contact/contact.page.tsx
  15. 12
      src/containers/Contact/hooks/use-contact.hook.ts
  16. 5
      src/containers/ContactsUsers/configs/columns.config.tsx
  17. 18
      src/containers/ContactsUsers/index.tsx
  18. 4
      src/containers/Factory/components/TreeFactory/index.tsx
  19. 7
      src/containers/GroupPermissions/components/create-edit-group-permissions/index.tsx
  20. 2
      src/containers/GroupPermissions/index.tsx
  21. 4
      src/containers/Ips/hooks/use-ips.hook.ts
  22. 14
      src/containers/Layout/index.tsx
  23. 12
      src/containers/Layout/topbar/TopbarProfile.tsx
  24. 51
      src/containers/Profile/components/CountTask/count-task.component.tsx
  25. 2
      src/containers/Profile/components/CountTask/style.scss
  26. 31
      src/containers/Profile/components/form-user/form-user.component.tsx
  27. 41
      src/containers/Profile/components/form-user/hooks/use-profile-form.hook.ts
  28. 37
      src/containers/Profile/components/profile-main.component.tsx
  29. 15
      src/containers/Tasks/components/print-tasks-item.component.tsx
  30. 15
      src/containers/Tasks/configs/selected-tasks-menu.config.ts
  31. 28
      src/containers/Tasks/configs/tasks-columns.config.tsx
  32. 4
      src/containers/Tasks/hooks/use-task-comments.hook.ts
  33. 27
      src/containers/Taxonomy/components/TreeTaxonomy/index.tsx
  34. 12
      src/containers/Taxonomy/components/TreeTaxonomy/style.scss
  35. 2
      src/containers/User/components/ExportExcel/ExportExcel.tsx
  36. 76
      src/containers/User/components/FormUser/index.tsx
  37. 10
      src/containers/User/configs/users-table-columns.config.tsx
  38. 3
      src/containers/User/hooks/use-create-edit-user.hook.ts
  39. 2
      src/containers/User/hooks/use-users-list.hook.tsx
  40. 4
      src/scss/component/sidebar.scss
  41. 4
      src/scss/settings/variable.scss
  42. 23
      src/services/domain/auth.service.ts
  43. 4
      src/services/domain/chats.service.ts
  44. 4
      src/services/domain/contact.service.ts
  45. 2
      src/services/domain/users.service.ts
  46. 1
      src/services/system/real-time.service.ts
  47. 1
      src/shared/enums/index.ts
  48. 4
      src/shared/enums/version.enum.ts
  49. 7
      src/shared/events/index.ts
  50. 11
      src/shared/helpers/chat.helpers.ts
  51. 2
      src/shared/helpers/permissions.helpers.ts
  52. 6
      src/shared/interfaces/user.interfaces.ts
  53. 120
      src/store/task/reducer.ts
  54. 190
      src/store/task/types.ts

2
src/api/contacts/requests.ts

@ -10,7 +10,7 @@ export const fetchContactsList = ( @@ -10,7 +10,7 @@ export const fetchContactsList = (
const reqParams = { ...params };
if (!params.sortField) {
reqParams.sort = "ASC";
reqParams.sortField = "firstName";
reqParams.sortField = "lastName";
}
return http.get<res.IFetchContactsList>(`admin/contacts`, {
params: reqParams

1
src/api/tasks-comments/responses.interfaces.ts

@ -9,6 +9,7 @@ export interface IComment { @@ -9,6 +9,7 @@ export interface IComment {
export interface IUserInComment {
userId: number;
firstName: string;
middleName: string;
lastName: string;
avatarUrl: string;
}

1
src/api/tasks/responses.interfaces.ts

@ -31,6 +31,7 @@ export interface IFetchExecutorsList @@ -31,6 +31,7 @@ export interface IFetchExecutorsList
export interface IUserInTask {
userId: number;
firstName: string;
middleName: string;
lastName: string;
position?: string;
}

6
src/api/tasks/transform.ts

@ -5,12 +5,12 @@ import { IExecutorsInListRes } from "./responses.interfaces"; @@ -5,12 +5,12 @@ import { IExecutorsInListRes } from "./responses.interfaces";
export const transformExecutorsToShortUsers = (
items: IExecutorsInListRes[]
): IShortUser[] => {
const transformedItems = items.map((it) => {
const transformedItems = items.map(it => {
return {
id: it.userId,
firstName: it.firstName,
fullName: createFullName(it.firstName, it.lastName),
avatarUrl: it.avatarUrl,
fullName: createFullName(it.firstName, it.middleName, it.lastName),
avatarUrl: it.avatarUrl
};
});

2
src/api/users/requests.ts

@ -10,7 +10,7 @@ const fetchUsersList = ( @@ -10,7 +10,7 @@ const fetchUsersList = (
const reqParams = { ...params };
if (!params.sortField) {
reqParams.sort = "ASC";
reqParams.sortField = "firstName";
reqParams.sortField = "lastName";
}
return http.get<Res.IFetchUsersList>(`admin/users`, { params: reqParams });
};

23
src/components/Forms/PhoneNumberController/index.tsx

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { InputMaskField, phoneNumberReg } from "@/shared";
import { InputMaskField } from "@/shared";
import React, { FC } from "react";
import { Controller } from "react-hook-form";
@ -8,7 +8,7 @@ interface PhoneNumberControllerProps { @@ -8,7 +8,7 @@ interface PhoneNumberControllerProps {
label: string;
validate: (value, name) => void;
className?: string;
rules?: boolean;
rules?: any;
}
export const PhoneNumberController: FC<PhoneNumberControllerProps> = ({
@ -24,17 +24,7 @@ export const PhoneNumberController: FC<PhoneNumberControllerProps> = ({ @@ -24,17 +24,7 @@ export const PhoneNumberController: FC<PhoneNumberControllerProps> = ({
<Controller
name={name}
control={form.control}
rules={
rules
? {
required: "Заповнити обов'язково",
pattern: {
value: phoneNumberReg,
message: "Номер не вірний",
},
}
: null
}
rules={rules ? rules : null}
render={({ field: { value, onChange }, fieldState }) => (
<InputMaskField
label={label}
@ -42,11 +32,12 @@ export const PhoneNumberController: FC<PhoneNumberControllerProps> = ({ @@ -42,11 +32,12 @@ export const PhoneNumberController: FC<PhoneNumberControllerProps> = ({
placeholder={"+38 (0xx) xxx xx xx"}
mask="+38 (999) 999 99 99"
onChange={async (value: string) => {
form.clearErrors(`${name}`);
const toSave = value.replace(/[^+\d]/g, "");
onChange(toSave);
if (!fieldState?.error?.message && value.length === 11)
validate(value, name);
// if (!fieldState?.error?.message && toSave.length > 11)
if (toSave.length > 11 || toSave.length === 3)
validate(toSave, name);
}}
error={fieldState?.error?.message}
/>

9
src/components/Modal/index.tsx

@ -86,9 +86,14 @@ class ModalComponent extends Component<any> { @@ -86,9 +86,14 @@ class ModalComponent extends Component<any> {
fontSize: 16,
fontWeight: "500",
color: "white",
width: "100%",
// width: "100%",
// maxWidth: "85%",
textAlign: "center",
marginLeft: 30,
marginLeft: 35,
textOverflow: "ellipsis",
overflow: "hidden",
flexGrow: 1,
padding: `0 5px`,
}}
>
{title}

23
src/components/SmartComponents/UserSelectWithSearch.tsx

@ -1,5 +1,10 @@ @@ -1,5 +1,10 @@
import { FC, useEffect, useMemo, useRef, useState } from "react";
import { EUsersListType, Option, usePaginationList } from "@/shared";
import {
createFullName,
EUsersListType,
Option,
usePaginationList,
} from "@/shared";
import React from "react";
import { Select, SelectProps, Spin } from "antd";
import { tasksApi, usersApi } from "@/api";
@ -59,14 +64,14 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({ @@ -59,14 +64,14 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({
fetchItems: fetchItemsByType[type],
serrializatorItems: (items) =>
items.map((it) => ({
title: `${it.firstName || ""} ${it.lastName || ""}`,
title: createFullName(it.firstName, it.middleName, it.lastName),
value:
type === EUsersListType.All ? it.id.toString() : it.userId.toString(),
})),
loadParams: {
limit: !_.isEmpty(defaultOptions) ? defaultOptions.length : limit,
count: defaultCount,
sortField: "firstName",
sortField: "lastName",
sort: "ASC",
name: searchString,
},
@ -83,7 +88,11 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({ @@ -83,7 +88,11 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({
if (_.isEmpty(data.items)) return;
const options = data.items.map((option) => ({
title: `${option.firstName || ""} ${option.lastName || ""}`,
title: createFullName(
option.firstName,
option.middleName,
option.lastName
),
value:
type === EUsersListType.All
? (option as IShortInfoUserRes).id.toString()
@ -205,7 +214,11 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({ @@ -205,7 +214,11 @@ export const UserSelectWithSearch: FC<IUserSelectWithSearchProps> = ({
value={account.id.toString()}
disabled={false}
>
{`${account.info.firstName || ""} ${account.info.lastName || ""}`}
{createFullName(
account.info.firstName,
account.info.middleName,
account.info.lastName
)}
</Select.Option>
)}

57
src/containers/Chats/hooks/use-chats-list.hook.ts

@ -6,7 +6,7 @@ import { @@ -6,7 +6,7 @@ import {
useEventsListener,
usePaginationList,
useSocket,
useSocketListener,
useSocketListener
} from "@/shared";
import { appEvents, SocketEvents } from "@/shared/events";
import { getProfile } from "@/store/account";
@ -29,9 +29,9 @@ export const useChatList = () => { @@ -29,9 +29,9 @@ export const useChatList = () => {
isLoading,
loadPage,
_setItems,
setOrderBy,
setOrderBy
} = usePaginationList<IChat>({
fetchItems: (params) => chatsService.fetchChats(params),
fetchItems: params => chatsService.fetchChats(params)
});
useEffect(() => {
@ -40,7 +40,7 @@ export const useChatList = () => { @@ -40,7 +40,7 @@ export const useChatList = () => {
}, [searchString]);
const presentInList = (chatId: number) => {
const chatIds = chats.map((it) => it.id);
const chatIds = chats.map(it => it.id);
return _.includes(chatIds, chatId);
};
@ -49,7 +49,15 @@ export const useChatList = () => { @@ -49,7 +49,15 @@ export const useChatList = () => {
};
const onDeleteChat = (data: { chatId: number }) => {
reloadIfIncludes(data?.chatId);
if (presentInList(Number(data?.chatId))) {
// *** при видаленні чату для себе або для всіх потрібно відразу забрати його зі списку
// бо перезавантаження чатів з серверу дає затримку і в цей час користувач може встигнути
// натиснути на цей видалений чат і відкрити його деталку *** //
_setItems(chats.filter(it => it.id !== data.chatId));
// *** перезавантаження списку з сервера все одно робимо, щоб отримати актуальний список
// чатів та правильний порядок закріплених чатів
resetFlatList();
}
};
const onEditChat = (data: { chatId: number }) => {
@ -57,21 +65,21 @@ export const useChatList = () => { @@ -57,21 +65,21 @@ export const useChatList = () => {
};
const onSetUnread = async (chatId: number, data?: Partial<IChat>) => {
const chat = _.find(chats, (chat) => chat.id === chatId);
const chat = _.find(chats, chat => chat.id === chatId);
if (!chat.isChatUnread) return setUnread(chatId);
if (data?.unreadMessagesCount > 0)
socket.emit("chat/read-chat", {
userId: accountId.id,
chatsIds: [chatId],
chatsIds: [chatId]
});
if (chat.isChatUnread) await chatsApi.setChatReadReq(chatId);
appEvents.emit("onReadChat", {
chatId,
unreadCount: data.unreadMessagesCount,
unreadCount: data.unreadMessagesCount
});
};
@ -80,7 +88,7 @@ export const useChatList = () => { @@ -80,7 +88,7 @@ export const useChatList = () => {
await chatsApi.setChatUnreadReq(chatId);
_setItems(
_.clone(chats).map((it) => {
_.clone(chats).map(it => {
if (it.id === chatId) it.isChatUnread = true;
return it;
})
@ -92,10 +100,10 @@ export const useChatList = () => { @@ -92,10 +100,10 @@ export const useChatList = () => {
const onPin = async (chatId: number) => {
try {
const chatIndex = chats.findIndex((item) => item.id === chatId);
const chatIndex = chats.findIndex(item => item.id === chatId);
if (chats[chatIndex].isChatFixed) return unPin(chatId);
const pinned = chats.filter((item) => item.isChatFixed);
const pinned = chats.filter(item => item.isChatFixed);
if (pinned.length > 4) {
// alert("max pinned chats 5!");
@ -104,7 +112,7 @@ export const useChatList = () => { @@ -104,7 +112,7 @@ export const useChatList = () => {
}
const lastPinnedIndex = chats.findIndex(
(item) => item.id === pinned[pinned.length - 1]?.id
item => item.id === pinned[pinned.length - 1]?.id
);
await chatsApi.pinChatReq({ chatId, order: lastPinnedIndex + 2 });
@ -124,14 +132,13 @@ export const useChatList = () => { @@ -124,14 +132,13 @@ export const useChatList = () => {
};
const isPinned = (chatId: number): boolean => {
const pinned =
chats.find((item) => item.id === chatId)?.isChatFixed || false;
const pinned = chats.find(item => item.id === chatId)?.isChatFixed || false;
return pinned;
};
const isUnread = (chatId: number): boolean => {
const readed =
chats.find((item) => item.id === chatId)?.isChatUnread || false;
chats.find(item => item.id === chatId)?.isChatUnread || false;
return readed;
};
@ -139,18 +146,18 @@ export const useChatList = () => { @@ -139,18 +146,18 @@ export const useChatList = () => {
(data: { chatId: number }) => {
const chat = _.find(
chats,
(chat) => Number(chat.id) === Number(data.chatId)
chat => Number(chat.id) === Number(data.chatId)
);
if (!chat || (chat?.unreadMessagesCount <= 0 && !chat?.isChatUnread))
return;
_setItems(
chats.map((it) => {
chats.map(it => {
if (Number(it.id) !== Number(data.chatId)) return it;
return {
...it,
unreadMessagesCount: 0,
isChatUnread: false,
isChatUnread: false
};
})
);
@ -179,7 +186,7 @@ export const useChatList = () => { @@ -179,7 +186,7 @@ export const useChatList = () => {
const onChatPinned = (data: SocketEvents["chat/pin"]) => {
const chat = _.find(
chats,
(chat) => chat.id.toString() === data.chatId.toString()
chat => chat.id.toString() === data.chatId.toString()
);
if (!chat || chat.isChatFixed) return;
@ -189,7 +196,7 @@ export const useChatList = () => { @@ -189,7 +196,7 @@ export const useChatList = () => {
const onChatUnpinned = (data: SocketEvents["chat/unpin"]) => {
const chat = _.find(
chats,
(chat) => chat.id.toString() === data.chatId.toString()
chat => chat.id.toString() === data.chatId.toString()
);
if (!chat || !chat.isChatFixed) return;
@ -200,13 +207,13 @@ export const useChatList = () => { @@ -200,13 +207,13 @@ export const useChatList = () => {
const onSetChatUnread = (data: SocketEvents["chat/unread"]) => {
const chat = _.find(
chats,
(chat) => chat.id.toString() === data.chatId.toString()
chat => chat.id.toString() === data.chatId.toString()
);
if (!chat || chat.isChatUnread) return;
_setItems(
_.clone(chats).map((it) => {
_.clone(chats).map(it => {
if (it.id.toString() === data.chatId.toString()) it.isChatUnread = true;
return it;
})
@ -242,12 +249,12 @@ export const useChatList = () => { @@ -242,12 +249,12 @@ export const useChatList = () => {
"onClearAllChats",
() => {
_setItems(
chats.map((it) => ({
chats.map(it => ({
...it,
lastMessage: null,
lastMessageDate: it.createdAt,
unreadMessagesCount: 0,
isChatUnread: false,
isChatUnread: false
}))
);
},
@ -303,6 +310,6 @@ export const useChatList = () => { @@ -303,6 +310,6 @@ export const useChatList = () => {
isPinned,
isUnread,
onPin,
onSetUnread,
onSetUnread
};
};

22
src/containers/Chats/modals/user-info.modal.tsx

@ -1,7 +1,13 @@ @@ -1,7 +1,13 @@
import { DateField } from "@/components/Fields";
import ModalComponent from "@/components/Modal";
import { chatsService, contactsService } from "@/services/domain";
import { FunctionalEmailField, InputField, IUser } from "@/shared";
import {
createFullName,
EUserStatus,
FunctionalEmailField,
InputField,
IUser,
} from "@/shared";
import _ from "lodash";
import React, { FC, useEffect, useState } from "react";
import { Avatar } from "../atoms";
@ -80,9 +86,11 @@ export const UserInfoModal: FC<UserInfoModalProps> = (props) => { @@ -80,9 +86,11 @@ export const UserInfoModal: FC<UserInfoModalProps> = (props) => {
<InputField
disabled
label="ПІБ"
value={`${user?.info?.firstName ? user?.info?.firstName : ""} ${
user?.info?.middleName ? user?.info?.middleName : ""
} ${user?.info?.lastName ? user?.info?.lastName : ""}`}
value={createFullName(
user?.info?.firstName,
user?.info?.middleName,
user?.info?.lastName
)}
onChange={_.noop}
/>
@ -142,12 +150,16 @@ export const UserInfoModal: FC<UserInfoModalProps> = (props) => { @@ -142,12 +150,16 @@ export const UserInfoModal: FC<UserInfoModalProps> = (props) => {
<FunctionalEmailField
label={"Email"}
value={user?.email}
onClick={() => window.open(`mailto:${user?.email}`)}
onClick={() => {
if (user?.status !== EUserStatus.Deleted)
window.open(`mailto:${user?.email}`);
}}
/>
<Button
color={"danger"}
onClick={onPressMessage}
disabled={user?.status === EUserStatus.Deleted}
className="user-info-btn info-right"
title="Надіслати повідомлення"
>

13
src/containers/Chats/plugins/chat-item.component.tsx

@ -51,6 +51,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => { @@ -51,6 +51,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
);
const menu = useMemo(() => {
if (_.isEmpty(items)) return <></>;
const menuItems = items.map((item) => ({
..._.pick(item, ["key", "label", "onClick"]),
icon: item.iconNode ? item.iconNode : null,
@ -107,12 +108,12 @@ export const ChatItem: FC<ChatItemProps> = (props) => { @@ -107,12 +108,12 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
};
const closeOtherMenu = () => {
const event = new Event('click')
document.dispatchEvent(event)
}
const event = new Event("click");
document.dispatchEvent(event);
};
const onContextMenu = (event) => {
closeOtherMenu()
closeOtherMenu();
if (event.target.id === "link") {
const linkValue = (event.target as Element).getAttribute("href");
setLinkValue(linkValue);
@ -120,8 +121,8 @@ export const ChatItem: FC<ChatItemProps> = (props) => { @@ -120,8 +121,8 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
setInnerVisible(true);
} else {
setLinkValue("");
setVisible(true);
setInnerVisible(false);
setVisible(true);
}
};
@ -149,7 +150,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => { @@ -149,7 +150,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
) : null}
<Dropdown
onVisibleChange={props.onMenuPress}
visible={visible}
visible={_.isEmpty(items) ? false : visible}
overlay={menu}
trigger={[`contextMenu`]}
>

4
src/containers/Chats/plugins/style.scss

@ -494,6 +494,7 @@ $bg-color-lighter: rgba(158, 39, 67, 0.1); @@ -494,6 +494,7 @@ $bg-color-lighter: rgba(158, 39, 67, 0.1);
align-items: center;
height: 40px;
width: 40px;
min-width: 40px;
margin-right: 10px;
border-radius: 50%;
border: 1px solid #7f7f7f;
@ -508,11 +509,14 @@ $bg-color-lighter: rgba(158, 39, 67, 0.1); @@ -508,11 +509,14 @@ $bg-color-lighter: rgba(158, 39, 67, 0.1);
flex-direction: column;
justify-content: center;
align-self: flex-start;
overflow: hidden;
p {
font-size: 12px;
line-height: 20px;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
}
}
}

11
src/containers/Contact/components/contact-main.component.tsx

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import React, { FC } from "react";
import { Card, CardBody, Col } from "reactstrap";
import { IUser } from "@/shared";
import { createFullName, IUser } from "@/shared";
import { Actions } from "./Actions";
import { Avatar } from "@/containers/Profile/components/avatar";
@ -41,8 +41,13 @@ export const ContactMain: FC<IProps> = ({ contact }) => { @@ -41,8 +41,13 @@ export const ContactMain: FC<IProps> = ({ contact }) => {
</div>
<div className="contact__data">
<p className="contact__name">{`${contact.info.firstName ||
""} ${contact.info.lastName || ""}`}</p>
<p className="contact__name">
{createFullName(
contact.info?.firstName,
contact.info?.middleName,
contact.info?.lastName
)}
</p>
<p
className="contact__work"
dangerouslySetInnerHTML={{

4
src/containers/Contact/contact.page.tsx

@ -8,9 +8,9 @@ import { useContact } from "./hooks/use-contact.hook"; @@ -8,9 +8,9 @@ import { useContact } from "./hooks/use-contact.hook";
export const ContactPage: FC = () => {
const location: any = useLocation();
const contact = location.state.contactinfo;
const contact = location.state?.contactinfo;
const { contactInfo } = useContact(contact.userId);
const { contactInfo } = useContact(contact?.userId);
return contactInfo ? (
<Container>

12
src/containers/Contact/hooks/use-contact.hook.ts

@ -3,14 +3,11 @@ import { contactsService, usersService, tasksService } from "@/services/domain"; @@ -3,14 +3,11 @@ import { contactsService, usersService, tasksService } from "@/services/domain";
import { ITasksCountsByAuthor, IUser, IUserStats } from "@/shared";
export const useContact = (contactId: number) => {
// const [isLoading, setLoad] = useState<boolean>(false);
const [contactInfo, setContactInfo] = useState<IUser>();
const [contactStats, setContactsStats] = useState<IUserStats>();
const [contactTasksCount, setContactTasksCount] = useState<
ITasksCountsByAuthor
>();
// const [needRefetch, setRefetch] = useState<boolean>(false);
const fetchContact = async () => {
try {
@ -32,21 +29,18 @@ export const useContact = (contactId: number) => { @@ -32,21 +29,18 @@ export const useContact = (contactId: number) => {
};
useEffect(() => {
fetchContact();
if (contactId) fetchContact();
}, []);
useEffect(() => {
fetchContactStats();
}, []);
useEffect(() => {
fetchContactTasksStats();
}, []);
return {
contactInfo,
contactStats,
contactTasksCount,
fetchContact
fetchContact,
fetchContactTasksStats
};
};

5
src/containers/ContactsUsers/configs/columns.config.tsx

@ -8,6 +8,7 @@ import { @@ -8,6 +8,7 @@ import {
} from "@/components/TableGrid/configs/void-row.config";
import { useHistory } from "react-router-dom";
import _ from "lodash";
import { createFullName } from "@/shared";
export const columnsConfig = () => {
const history = useHistory();
@ -55,7 +56,7 @@ export const columnsConfig = () => { @@ -55,7 +56,7 @@ export const columnsConfig = () => {
{
name: "П.І.Б.",
key: "name",
sortKey: "firstName", // допоміжне поле, використовується, якщо ключ для сортування по цьому полю
sortKey: "lastName", // допоміжне поле, використовується, якщо ключ для сортування по цьому полю
// (назва поля по якому треба сортувати) відрізняється від поля key
// width: 260,
resizable: true,
@ -68,7 +69,7 @@ export const columnsConfig = () => { @@ -68,7 +69,7 @@ export const columnsConfig = () => {
<div className="info">
<div className="ellipsis" style={{ cursor: "pointer" }}>
<span className="full-name">
{row.firstName || ""} {row.lastName || ""}
{createFullName(row.firstName, row.middleName, row.lastName)}
</span>
</div>
<span className="position ellipsis">{row.position}</span>

18
src/containers/ContactsUsers/index.tsx

@ -35,7 +35,7 @@ export const ContactsUsers = () => { @@ -35,7 +35,7 @@ export const ContactsUsers = () => {
loadParams: {
limit: 10,
page: 1,
sortField: "firstName",
sortField: "lastName",
sort: "ASC",
},
});
@ -92,14 +92,14 @@ export const ContactsUsers = () => { @@ -92,14 +92,14 @@ export const ContactsUsers = () => {
columns={columnsConfig()}
paginationList={paginationList}
activeColumns={defaultActiveColumnsConfig}
onRowClick={(idx, { userId, firstName, lastName }) => {
console.log(
idx,
{ userId: userId },
{ firstName: firstName },
{ lastName: lastName }
);
}}
// onRowClick={(idx, { userId, firstName, lastName }) => {
// console.log(
// idx,
// { userId: userId },
// { firstName: firstName },
// { lastName: lastName }
// );
// }}
focusedFilterField={focusFilterKey}
onFocusFilterField={(fieldKey: string) =>
setFocusFilterKey(fieldKey)

4
src/containers/Factory/components/TreeFactory/index.tsx

@ -181,7 +181,9 @@ export const TreeFactory: FC<IProps> = ({ @@ -181,7 +181,9 @@ export const TreeFactory: FC<IProps> = ({
const renderTree = useCallback(
(preparedTree, isChildren?: boolean) => {
if (Array.isArray(preparedTree)) {
return preparedTree.map((item) => (
return _.sortBy(preparedTree, (factory) =>
factory.name.toLowerCase()
).map((item) => (
<Tree.TreeNode
className={isChildren ? "tree-node_children" : "tree-node"}
style={{

7
src/containers/GroupPermissions/components/create-edit-group-permissions/index.tsx

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
import React, { FC, useEffect } from "react";
import {
createFullName,
getParentsTree,
InputField,
notification,
@ -42,7 +43,11 @@ export const CreateEditGroupPermissionsForm: FC<CreateGroupPermissionsFormProps> @@ -42,7 +43,11 @@ export const CreateEditGroupPermissionsForm: FC<CreateGroupPermissionsFormProps>
fetchItems: usersApi.fetchUsersList,
serrializatorItems: (items) =>
items.map((it) => ({
title: `${it.info.firstName || ""} ${it.info.lastName || ""}`,
title: createFullName(
it.info.firstName,
it.info.middleName,
it.info.lastName
),
value: it.id,
})),
});

2
src/containers/GroupPermissions/index.tsx

@ -52,7 +52,7 @@ export const GroupPermission: FC = () => { @@ -52,7 +52,7 @@ export const GroupPermission: FC = () => {
limit: 10,
page: 1,
sort: "ASC",
sortField: "id",
sortField: "name",
},
});

4
src/containers/Ips/hooks/use-ips.hook.ts

@ -35,7 +35,9 @@ export const useIPs = () => { @@ -35,7 +35,9 @@ export const useIPs = () => {
loadParams: {
limit: 10,
page: 1,
type: listType
type: listType,
sort: "ASC",
sortField: "ip"
}
});

14
src/containers/Layout/index.tsx

@ -12,11 +12,15 @@ import { @@ -12,11 +12,15 @@ import {
} from "@/store/shared";
import { simpleDispatch } from "@/store/store-helpers";
import { SocketIo } from "@/services/system";
import { useSocketListener } from "@/shared";
import { permissionsService } from "@/services/domain";
import { EntityType, useSocketListener } from "@/shared";
import { accountService, permissionsService } from "@/services/domain";
import { ContentModalSmart } from "@/smart-components/content-modal";
import { getProfile } from "@/store/account";
import { SocketEvents } from "@/shared/events";
export const Layout = () => {
const profile = useSelector(getProfile);
useEffect(() => {
const socketIo = SocketIo.get();
@ -27,7 +31,13 @@ export const Layout = () => { @@ -27,7 +31,13 @@ export const Layout = () => {
await permissionsService.loadMyPermissions();
};
const onAccountChange = async (data: SocketEvents["version"]) => {
if (data.type === EntityType.User && data.entityId === profile.id)
await accountService.getAccount();
};
useSocketListener("user/change-permissions", onPermissionsChanged, []);
useSocketListener("version", onAccountChange, [profile]);
const sidebarState = useSelector(getSidebar);

12
src/containers/Layout/topbar/TopbarProfile.tsx

@ -9,7 +9,7 @@ import { getRefreshToken } from "@/store/auth"; @@ -9,7 +9,7 @@ import { getRefreshToken } from "@/store/auth";
import default_avatar from "@/assets/img/default-avatar.jpg";
import { RouteEnum } from "@/containers/App/router";
import downIcon from "../../../assets/img/Vector.svg";
import { ConfirmModal } from "@/shared";
import { ConfirmModal, createFullName } from "@/shared";
import _ from "lodash";
import { useHistory } from "react-router-dom";
@ -50,9 +50,13 @@ export const TopBarProfile = () => { @@ -50,9 +50,13 @@ export const TopBarProfile = () => {
<img src={userAvatar} alt="avatar" />
</div>
<p className="topbar__avatar-name">{`${profile.info?.firstName ||
""} ${profile.info?.lastName || ""} ${profile.info?.middleName ||
""}`}</p>
<p className="topbar__avatar-name">
{createFullName(
profile.info?.firstName,
profile.info?.middleName,
profile.info?.lastName
)}
</p>
<img src={downIcon} alt="" className="topbar__icon" />
</button>
{collapse && (

51
src/containers/Profile/components/CountTask/count-task.component.tsx

@ -17,10 +17,14 @@ interface IProps { @@ -17,10 +17,14 @@ interface IProps {
countTaskStats?: ITasksCountsByAuthor;
}
interface ICountTasksForm {
from: Date;
to: Date;
}
export const CountTask: FC<IProps> = ({
profile,
authProfile,
countTaskStats,
}) => {
const [dateValues, setDateValues] = useState({
@ -41,29 +45,26 @@ export const CountTask: FC<IProps> = ({ @@ -41,29 +45,26 @@ export const CountTask: FC<IProps> = ({
content: () => componentRef.current,
});
const { control, getValues } = useForm<{
startDate: Date;
endDate: Date;
}>();
const { control, getValues, handleSubmit } = useForm<ICountTasksForm>({
defaultValues: { from: null, to: null },
});
const submitSearchTasks = async () => {
const submitSearchTasks = async (data: ICountTasksForm) => {
try {
const { startDate: start, endDate: end } = getValues();
const preparedValues = {
from: moment(start).format("YYYY-MM-DD"),
to: moment(end).format("YYYY-MM-DD"),
from: moment(data.from).format("YYYY-MM-DD"),
to: moment(data.to).format("YYYY-MM-DD"),
};
const preparedforPrintValues = {
from: start,
to: end,
const preparedForPrintValues = {
from: data.from,
to: data.to,
};
const resultSearch = await tasksService.fetchTasksCountsByAuthor(
profile.id,
preparedValues
);
await setDateValues(preparedforPrintValues);
await setDateValues(preparedForPrintValues);
await setCountTasksStats(resultSearch);
} catch (e) {
return console.log("error fetching tasks count", e);
@ -77,7 +78,7 @@ export const CountTask: FC<IProps> = ({ @@ -77,7 +78,7 @@ export const CountTask: FC<IProps> = ({
});
};
const { startDate: start } = getValues();
const { from } = getValues();
return (
<div className="count-task-user">
@ -89,9 +90,10 @@ export const CountTask: FC<IProps> = ({ @@ -89,9 +90,10 @@ export const CountTask: FC<IProps> = ({
<div className="form-content">
<div className="start-date">
<Controller
name={"startDate"}
name={"from"}
control={control}
render={({ field: { value, onChange } }) => (
rules={{ required: "Заповнити обов'язково" }}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<DateField
label={"Початок"}
value={_.isEmpty(value) ? "" : value}
@ -99,6 +101,9 @@ export const CountTask: FC<IProps> = ({ @@ -99,6 +101,9 @@ export const CountTask: FC<IProps> = ({
onChange(date);
handleDateChange("from", value);
}}
meta={{
error: error?.message,
}}
disabledDate={(current) => current.isAfter(moment())}
/>
)}
@ -107,9 +112,10 @@ export const CountTask: FC<IProps> = ({ @@ -107,9 +112,10 @@ export const CountTask: FC<IProps> = ({
<div className="end-date">
<Controller
name={"endDate"}
name={"to"}
control={control}
render={({ field: { value, onChange } }) => (
rules={{ required: "Заповнити обов'язково" }}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<DateField
label={"Кінець"}
value={_.isEmpty(value) ? "" : value}
@ -117,7 +123,10 @@ export const CountTask: FC<IProps> = ({ @@ -117,7 +123,10 @@ export const CountTask: FC<IProps> = ({
onChange(date);
handleDateChange("to", value);
}}
disabledDate={(current) => current.isBefore(start)}
meta={{
error: error?.message,
}}
disabledDate={(current) => current.isBefore(from)}
/>
)}
/>
@ -125,7 +134,7 @@ export const CountTask: FC<IProps> = ({ @@ -125,7 +134,7 @@ export const CountTask: FC<IProps> = ({
</div>
<div className="search-btn">
<Button
onClick={submitSearchTasks}
onClick={handleSubmit(submitSearchTasks)}
className="btn btn-primary"
type="button"
>

2
src/containers/Profile/components/CountTask/style.scss

@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
.start-date {
margin-right: 10px;
width: 50%;
.ant-picker-suffix {
content: url(/assets/img/icon-calendar.svg);
@ -42,6 +43,7 @@ @@ -42,6 +43,7 @@
.end-date {
margin-left: 10px;
width: 50%;
.ant-picker-suffix {
content: url(/assets/img/icon-calendar.svg);

31
src/containers/Profile/components/form-user/form-user.component.tsx

@ -49,6 +49,7 @@ export const FormUser: FC<IProps> = ({ @@ -49,6 +49,7 @@ export const FormUser: FC<IProps> = ({
isDisableBtns,
sendPasswordToEmail,
getValues,
setError,
} = useProfileForm({
profile,
authId: authProfileId,
@ -119,6 +120,7 @@ export const FormUser: FC<IProps> = ({ @@ -119,6 +120,7 @@ export const FormUser: FC<IProps> = ({
placeholder={"Email"}
label={"Email"}
onChange={(text) => {
setError({ ...errors, email: "" });
onChange(text);
validateEmail(text);
}}
@ -135,7 +137,12 @@ export const FormUser: FC<IProps> = ({ @@ -135,7 +137,12 @@ export const FormUser: FC<IProps> = ({
<Controller
name="dateOfBirth"
control={control}
rules={{ required: "Заповнити обов'язково" }}
rules={{
required: "Заповнити обов'язково",
validate: (val) =>
moment.utc().subtract(18, "years") > moment(val) ||
"Вік не може бути менше 18 років",
}}
render={({ field: { value, onChange }, fieldState }) => (
<DateField
label={"Дата народження"}
@ -161,6 +168,9 @@ export const FormUser: FC<IProps> = ({ @@ -161,6 +168,9 @@ export const FormUser: FC<IProps> = ({
value: phoneNumberReg,
message: "Номер не вірний",
},
validate: (val: string) =>
val !== getValues("personalPhoneNumber") ||
"Не може співпадати з особистим номером",
}}
render={({ field: { value, onChange }, fieldState }) => {
return (
@ -172,6 +182,10 @@ export const FormUser: FC<IProps> = ({ @@ -172,6 +182,10 @@ export const FormUser: FC<IProps> = ({
placeholder={"+38 (0xx) xxx xx xx"}
mask="+38 (999) 999 99 99"
onChange={(text) => {
setError({
...errors,
phoneNumber: "",
});
onChange(text.replace(/[^+\d]/g, ""));
validatePhoneNumber(text);
}}
@ -207,6 +221,19 @@ export const FormUser: FC<IProps> = ({ @@ -207,6 +221,19 @@ export const FormUser: FC<IProps> = ({
<Controller
name="personalPhoneNumber"
control={control}
rules={{
pattern: {
value: phoneNumberReg,
message: "Номер не вірний",
},
validate: (val: string) => {
if (!val) return true;
return (
val !== getValues("phoneNumber") ||
"Не може співпадати з робочим номером"
);
},
}}
render={({ field: { value, onChange }, fieldState }) => (
<InputMaskField
error={
@ -217,6 +244,7 @@ export const FormUser: FC<IProps> = ({ @@ -217,6 +244,7 @@ export const FormUser: FC<IProps> = ({
placeholder={"+38 (0xx) xxx xx xx"}
mask="+38 (999) 999 99 99"
onChange={(text) => {
setError({ ...errors, personalPhoneNumber: "" });
onChange(text.replace(/[^+\d]/g, ""));
validatePersonalPhoneNumber(text);
}}
@ -279,6 +307,7 @@ export const FormUser: FC<IProps> = ({ @@ -279,6 +307,7 @@ export const FormUser: FC<IProps> = ({
label={"Логін"}
error={fieldState?.error?.message || errors["loginExist"]}
onChange={(text) => {
setError({ ...errors, loginExist: "" });
onChange(text);
validateLogin(text);
}}

41
src/containers/Profile/components/form-user/hooks/use-profile-form.hook.ts

@ -98,14 +98,9 @@ export const useProfileForm = ({ @@ -98,14 +98,9 @@ export const useProfileForm = ({
};
}, [profile]);
const {
control,
watch,
handleSubmit,
setValue,
getValues,
formState
} = useForm<IProfileForm>({
const { control, watch, handleSubmit, setValue, getValues } = useForm<
IProfileForm
>({
defaultValues: preparedDefaultValues
});
@ -212,10 +207,9 @@ export const useProfileForm = ({ @@ -212,10 +207,9 @@ export const useProfileForm = ({
});
if (existLogin.login && profile.login !== value) {
setError({ ...errors, loginExist: "Такий логін вже існує" });
} else {
setError({ ...errors, loginExist: "" });
// } else {
// setError({ ...errors, loginExist: "" });
}
// console.log("existLogin", existLogin);
};
const validatePhoneNumber = async value => {
@ -229,11 +223,11 @@ export const useProfileForm = ({ @@ -229,11 +223,11 @@ export const useProfileForm = ({
Number(telPhone) !== Number(profile.phoneNumber)
) {
setError({ ...errors, phoneNumber: "Такий номер телефону вже існує" });
} else {
setError({
...errors,
phoneNumber: ""
});
// } else {
// setError({
// ...errors,
// phoneNumber: ""
// });
}
};
const validatePersonalPhoneNumber = async value => {
@ -252,10 +246,9 @@ export const useProfileForm = ({ @@ -252,10 +246,9 @@ export const useProfileForm = ({
...errors,
personalPhoneNumber: "Такий номер телефону вже існує"
});
} else {
setError({ ...errors, personalPhoneNumber: "" });
// } else {
// setError({ ...errors, personalPhoneNumber: "" });
}
// console.log("existPersPhoneNumber", existPersPhoneNumber);
};
const validateEmail = async value => {
@ -264,11 +257,10 @@ export const useProfileForm = ({ @@ -264,11 +257,10 @@ export const useProfileForm = ({
email: value
});
if (existEmail?.email && profile?.email !== value) {
setError({ ...errors, email: "Такий email вже існує" });
} else {
setError({ ...errors, email: "" });
setError({ ...errors, email: "Такий пошта вже існує" });
// } else {
// setError({ ...errors, email: "" });
}
// console.log("existEmail", existEmail);
};
const submitChageAccount = async () => {
@ -388,6 +380,7 @@ export const useProfileForm = ({ @@ -388,6 +380,7 @@ export const useProfileForm = ({
validatePersonalPhoneNumber,
validateEmail,
sendPasswordToEmail,
getValues
getValues,
setError
};
};

37
src/containers/Profile/components/profile-main.component.tsx

@ -1,7 +1,12 @@ @@ -1,7 +1,12 @@
import React, { FC } from "react";
import { Card, CardBody, Col } from "reactstrap";
import _ from "lodash";
import { ITasksCountsByAuthor, IUser, IUserStats } from "@/shared";
import {
createFullName,
ITasksCountsByAuthor,
IUser,
IUserStats,
} from "@/shared";
import { CountUser } from "./count";
import { Avatar } from "./avatar";
import { Actions } from "./Actions";
@ -51,8 +56,13 @@ export const ProfileMain: FC<IProps> = ({ @@ -51,8 +56,13 @@ export const ProfileMain: FC<IProps> = ({
</div>
<div className="profile__data">
<p className="profile__name">{`${profile.info.firstName ||
""} ${profile.info.lastName || ""}`}</p>
<p className="profile__name">
{createFullName(
profile.info?.firstName,
profile.info?.middleName,
profile.info?.lastName
)}
</p>
<p className="profile__work">
{(profile.factoryName ? `${profile.factoryName}, ` : "") +
`${profile.info.position}`}
@ -97,21 +107,12 @@ export const ProfileMain: FC<IProps> = ({ @@ -97,21 +107,12 @@ export const ProfileMain: FC<IProps> = ({
/>
<Col md={12} lg={12} xl={12} style={{ marginBottom: "40px" }}>
{!_.isEmpty(countTasksStats) ? (
<CountTask
profile={profile}
authProfile={authProfile}
onSubmit={() => {}}
countTaskStats={countTasksStats}
/>
) : (
<CountTask
profile={profile}
authProfile={authProfile}
onSubmit={() => {}}
countTaskStats={{ unique: 0, duplicate: 0, personal: 0, all: 0 }}
/>
)}
<CountTask
profile={profile}
authProfile={authProfile}
onSubmit={() => {}}
countTaskStats={{ unique: 0, duplicate: 0, personal: 0, all: 0 }}
/>
</Col>
</>
);

15
src/containers/Tasks/components/print-tasks-item.component.tsx

@ -32,8 +32,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => { @@ -32,8 +32,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => {
<strong>
<span style={{ textDecoration: "underline" }}>
{createFullName(
task?.executor?.firstName,
task?.executor?.lastName
task.executor?.firstName,
task.executor?.middleName,
task.executor?.lastName
)}
</span>
</strong>{" "}
@ -123,8 +124,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => { @@ -123,8 +124,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => {
<td colSpan={3} style={styles.td}>
<strong>Ініціатор: </strong>
{createFullName(
task?.initiator?.firstName,
task?.initiator?.lastName
task.initiator?.firstName,
task.initiator?.middleName,
task.initiator?.lastName
)}
</td>
<td></td>
@ -200,8 +202,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => { @@ -200,8 +202,9 @@ export const PrintTasksItem: FC<IProps> = ({ task }) => {
>
<td>
{createFullName(
item.author?.firstName,
item.author?.lastName
task.author?.firstName,
task.author?.middleName,
task.author?.lastName
)}
:
</td>

15
src/containers/Tasks/configs/selected-tasks-menu.config.ts

@ -123,7 +123,20 @@ export const getSelectedTasksMenuConfig = ( @@ -123,7 +123,20 @@ export const getSelectedTasksMenuConfig = (
items.push(menuItems.finish);
}
if (_.every(props.selectedItems, it => it.status === ETaskStatus.Active)) {
if (
_.every(
props.selectedItems,
it =>
it.status === ETaskStatus.Active &&
checkPermission(
"user",
it?.executorId,
props.profile,
props.permissions,
Permissions.DESTROY
)
)
) {
items.push(menuItems.reassign);
}

28
src/containers/Tasks/configs/tasks-columns.config.tsx

@ -4,7 +4,7 @@ import ClipSVGIcon from "../../../assets/img/clip.svg"; @@ -4,7 +4,7 @@ import ClipSVGIcon from "../../../assets/img/clip.svg";
import StarFilled from "../../../assets/img/starFilled.svg";
import moment from "moment";
import { voidColumn } from "@/components/TableGrid/configs/void-row.config";
import { ITask, notification } from "@/shared";
import { createFullName, ITask, notification } from "@/shared";
import { CommentIcon, StarIcon } from "@/shared/components/icons";
import { tasksService } from "@/services/domain";
import _ from "lodash";
@ -225,9 +225,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => { @@ -225,9 +225,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => {
style={{ width: "100%", height: "100%" }}
onClick={(e) => onPressName(row, e)}
>
{row.author
? `${row.author?.firstName || ""} ${row.author?.lastName || ""}`
: ""}
{createFullName(
row.author?.firstName,
row.author?.middleName,
row.author?.lastName
)}
</div>
</Popover>
),
@ -253,10 +255,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => { @@ -253,10 +255,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => {
style={{ width: "100%", height: "100%" }}
onClick={(e) => onPressName(row, e)}
>
{row.executor
? `${row.executor?.firstName || ""} ${row.executor?.lastName ||
""}`
: ""}
{createFullName(
row.executor?.firstName,
row.executor?.middleName,
row.executor?.lastName
)}
</div>
</Popover>
),
@ -283,10 +286,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => { @@ -283,10 +286,11 @@ export const getTasksColumnsConfig: any = ({ onPressName }: IProps) => {
style={{ width: "100%", height: "100%" }}
onClick={(e) => onPressName(row, e)}
>
{row.initiator
? `${row.initiator?.firstName || ""} ${row.initiator?.lastName ||
""}`
: ""}
{createFullName(
row.initiator?.firstName,
row.initiator?.middleName,
row.initiator?.lastName
)}
</div>
</Popover>
),

4
src/containers/Tasks/hooks/use-task-comments.hook.ts

@ -139,7 +139,9 @@ export const useTaskComments = ({ taskId, needInit }: IProps) => { @@ -139,7 +139,9 @@ export const useTaskComments = ({ taskId, needInit }: IProps) => {
}
];
appEvents.emit("openMessageMenuOptions", { items: options as any });
appEvents.emit("openMessageMenuOptions", {
items: comment.authorId === account.id ? (options as any) : []
});
};
const cancelEdit = () => {

27
src/containers/Taxonomy/components/TreeTaxonomy/index.tsx

@ -1,12 +1,11 @@ @@ -1,12 +1,11 @@
import React, { useEffect, useState } from "react";
import { Tree, Popconfirm } from "antd";
import { Tree, Popconfirm, Spin } from "antd";
import { genTree } from "../../../../lib/helper";
import _ from "lodash";
import "./style.scss";
import {
ITaxonomy,
IUser,
Loader,
ETaxonomyType,
ConfirmModal,
notification,
@ -195,17 +194,17 @@ export const TreeTaxonomy = (props: IProps) => { @@ -195,17 +194,17 @@ export const TreeTaxonomy = (props: IProps) => {
);
const renderTree = (tree: any) => {
return tree.map((item) => {
return (
<Tree.TreeNode title={renderTitle(item)} key={item.id}>
{item.children && renderTree(item.children)}
</Tree.TreeNode>
);
});
return _.sortBy(tree, (taxonomy) => taxonomy.name.toLowerCase()).map(
(item) => {
return (
<Tree.TreeNode title={renderTitle(item)} key={item.id}>
{item.children && renderTree(item.children)}
</Tree.TreeNode>
);
}
);
};
if (props.isLoading) return <Loader />;
const deleteTaxonomy = async () => {
try {
await taxonomiesService.deleteTaxonomy(taxonomyIdToDelete);
@ -221,6 +220,12 @@ export const TreeTaxonomy = (props: IProps) => { @@ -221,6 +220,12 @@ export const TreeTaxonomy = (props: IProps) => {
return (
<div className="TreeTaxonomy">
{props.isLoading && (
<div className="taxonomy-spinner">
<Spin />
</div>
)}
<ConfirmModal
isShow={isOpenConfirmModal}
message={`Ви справді хочете видалити ${

12
src/containers/Taxonomy/components/TreeTaxonomy/style.scss

@ -4,6 +4,7 @@ $down-icon-color: #282828; @@ -4,6 +4,7 @@ $down-icon-color: #282828;
.TreeTaxonomy {
padding: 20px;
position: relative;
.ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected,
.ant-tree li .ant-tree-node-content-wrapper:hover {
@ -178,4 +179,15 @@ $down-icon-color: #282828; @@ -178,4 +179,15 @@ $down-icon-color: #282828;
supported by Chrome, Edge, Opera and Firefox */
}
}
.taxonomy-spinner {
position: absolute;
display: flex;
// align-items: center;
justify-content: center;
z-index: 2;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.4);
}
}

2
src/containers/User/components/ExportExcel/ExportExcel.tsx

@ -141,7 +141,7 @@ export const ExportExcel = ({ type }: IProps) => { @@ -141,7 +141,7 @@ export const ExportExcel = ({ type }: IProps) => {
}
return {
ФІО: createUserName(user.firstName, user.middleName, user.lastName),
ПІБ: createUserName(user.firstName, user.middleName, user.lastName),
Логін: user.login,
Пошта: user.email,
Телефон: user.phoneNumber,

76
src/containers/User/components/FormUser/index.tsx

@ -15,6 +15,7 @@ import { @@ -15,6 +15,7 @@ import {
IUser,
loginPattern,
Permissions,
phoneNumberReg,
SelectAvatar,
SelectField,
} from "@/shared";
@ -27,6 +28,7 @@ import { UserModalMode } from "../../enums"; @@ -27,6 +28,7 @@ import { UserModalMode } from "../../enums";
import { PermissionsPage } from "@/containers/Permissions";
import { PhoneNumberController } from "@/components/Forms/PhoneNumberController";
import default_avatar from "@/assets/img/default-avatar.jpg";
import moment from "moment";
interface IProps {
profile: IUser;
@ -62,17 +64,26 @@ export const FormUser = (props: IProps) => { @@ -62,17 +64,26 @@ export const FormUser = (props: IProps) => {
form.control._formValues.factory
);
const handleSubmit = (e: any) => {
e.preventDefault();
if (!_.isEmpty(errors)) {
setActiveTab("1");
return;
}
submit(e);
};
return (
<form
className="form"
style={{ flexDirection: "column" }}
onSubmit={(e) => {
e.preventDefault();
console.log("errors", errors);
if (!_.isEmpty(errors)) {
setActiveTab("1");
return;
}
submit(e);
} else submit(e);
}}
>
<div className="tabs tabs--justify tabs--bordered-modal">
@ -208,6 +219,7 @@ export const FormUser = (props: IProps) => { @@ -208,6 +219,7 @@ export const FormUser = (props: IProps) => {
placeholder={"Email"}
label={"Email"}
onChange={async (value: string) => {
form.clearErrors("email");
onChange(value);
if (emailPattern.test(value))
await validate(value, "email");
@ -220,7 +232,12 @@ export const FormUser = (props: IProps) => { @@ -220,7 +232,12 @@ export const FormUser = (props: IProps) => {
<Controller
name="dateOfBirth"
control={form.control}
rules={{ required: "Заповнити обов'язково" }}
rules={{
required: "Заповнити обов'язково",
validate: (val) =>
moment.utc().subtract(18, "years") > moment(val) ||
"Вік не може бути менше 18 років",
}}
render={({ field: { value, onChange }, fieldState }) => (
<DateField
label={"Дата народження"}
@ -230,6 +247,7 @@ export const FormUser = (props: IProps) => { @@ -230,6 +247,7 @@ export const FormUser = (props: IProps) => {
meta={{
error: fieldState?.error?.message,
}}
disabledDate={(current) => current.isAfter(moment())}
/>
)}
/>
@ -287,6 +305,7 @@ export const FormUser = (props: IProps) => { @@ -287,6 +305,7 @@ export const FormUser = (props: IProps) => {
placeholder={"Логін"}
label={"Логін"}
onChange={async (value: string) => {
form.clearErrors("login");
onChange(value);
if (loginPattern.test(value))
await validate(value, "login");
@ -300,7 +319,16 @@ export const FormUser = (props: IProps) => { @@ -300,7 +319,16 @@ export const FormUser = (props: IProps) => {
</div>
<div className="contact-row-field">
<PhoneNumberController
rules
rules={{
required: "Заповнити обов'язково",
pattern: {
value: phoneNumberReg,
message: "Номер не вірний",
},
validate: (val: string) =>
val !== form.getValues("personalPhoneNumber") ||
"Не може співпадати з особистим номером",
}}
form={form}
name="phoneNumber"
label={"Телефон робочий"}
@ -308,6 +336,19 @@ export const FormUser = (props: IProps) => { @@ -308,6 +336,19 @@ export const FormUser = (props: IProps) => {
className="col-12 col-md-6 contact-left-field"
/>
<PhoneNumberController
rules={{
pattern: {
value: phoneNumberReg,
message: "Номер не вірний",
},
validate: (val: string) => {
if (!val) return true;
return (
val !== form.getValues("phoneNumber") ||
"Не може співпадати з робочим номером"
);
},
}}
form={form}
name="personalPhoneNumber"
label={"Телефон особистий"}
@ -445,7 +486,8 @@ export const FormUser = (props: IProps) => { @@ -445,7 +486,8 @@ export const FormUser = (props: IProps) => {
</div>
<ButtonToolbar className="form__button-toolbar">
<Button
onClick={submit}
// onClick={submit}
onClick={handleSubmit}
color="primary"
type="submit"
className="contact__btn"
@ -458,9 +500,15 @@ export const FormUser = (props: IProps) => { @@ -458,9 +500,15 @@ export const FormUser = (props: IProps) => {
color="primary"
type="button"
disabled={isDisableBtns}
onClick={() => {
form.setValue("sendPasswordBy", "email");
submit();
onClick={(e) => {
e.preventDefault();
if (!_.isEmpty(errors)) {
setActiveTab("1");
return;
} else {
form.setValue("sendPasswordBy", "email");
submit(e);
}
}}
>
Зберегти <i style={{ marginLeft: 10 }} className="fal fa-envelope" />
@ -471,9 +519,15 @@ export const FormUser = (props: IProps) => { @@ -471,9 +519,15 @@ export const FormUser = (props: IProps) => {
color="primary"
type="button"
disabled={isDisableBtns}
onClick={() => {
form.setValue("sendPasswordBy", "sms");
submit();
onClick={(e) => {
e.preventDefault();
if (!_.isEmpty(errors)) {
setActiveTab("1");
return;
} else {
form.setValue("sendPasswordBy", "sms");
submit(e);
}
}}
>
Зберегти <i style={{ marginLeft: 10 }} className="fal fa-sms" />

10
src/containers/User/configs/users-table-columns.config.tsx

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import React from "react";
import { voidColumn } from "@/components/TableGrid/configs";
import { useHistory } from "react-router-dom";
import { EUserStatus, IUser } from "@/shared";
import { createFullName, EUserStatus, IUser } from "@/shared";
import moment from "moment";
import _ from "lodash";
@ -46,7 +46,7 @@ export const usersTableColumns = () => { @@ -46,7 +46,7 @@ export const usersTableColumns = () => {
key: "name",
resizable: true,
sortable: true,
sortKey: "firstName",
sortKey: "lastName",
width: 160,
filter: true,
filterType: "search",
@ -62,7 +62,11 @@ export const usersTableColumns = () => { @@ -62,7 +62,11 @@ export const usersTableColumns = () => {
: "full-name-blocked"
}
>
{row.info?.firstName || ""} {row.info?.lastName || ""}
{createFullName(
row.info?.firstName,
row.info?.middleName,
row.info?.lastName
)}
</span>
</div>
<span

3
src/containers/User/hooks/use-create-edit-user.hook.ts

@ -121,7 +121,8 @@ export const useCreateEditUser = ({ @@ -121,7 +121,8 @@ export const useCreateEditUser = ({
});
if (exist[key])
setError(key, { message: `Такий ${fieldNameByKey[key]} вже існує` });
else clearErrors(key);
// else
// clearErrors(key);
}
};

2
src/containers/User/hooks/use-users-list.hook.tsx

@ -39,7 +39,7 @@ export const useUsersList = () => { @@ -39,7 +39,7 @@ export const useUsersList = () => {
limit: 10,
page: 1,
sort: "ASC",
sortField: "firstName",
sortField: "lastName",
},
});

4
src/scss/component/sidebar.scss

@ -271,6 +271,10 @@ @@ -271,6 +271,10 @@
left: 75px;
top: 63%
}
.sidebar__submenu {
padding-top: 0;
}
}
@media screen and (min-width: 576px) {

4
src/scss/settings/variable.scss

@ -9,7 +9,7 @@ $themes: ( @@ -9,7 +9,7 @@ $themes: (
defaultColorText: #000000,
colorTextAdditional: #646777,
logoImg: url(../../assets/img/logo_rwsx4.png),
colorHover: #fafbfe,
colorHover: rgba(158, 39, 67, 0.1),
colorFolderHover: #f0eeee,
colorBorder: #eff1f5,
colorIcon: #dddddd,
@ -65,7 +65,7 @@ $color-secondary: #F8F8F8; @@ -65,7 +65,7 @@ $color-secondary: #F8F8F8;
$color-secondary-hover: darken($color-secondary, 10%);
$color-additional-text: #7F7F7F;
$color-accent: #3498DB;
$color-accent: #9e2743;
$color-accent-hover: darken($color-accent, 10%);
$color-additional: #999999;
$color-additional-hover: darken($color-additional, 10%);

23
src/services/domain/auth.service.ts

@ -2,8 +2,11 @@ import { authApi } from "@/api"; @@ -2,8 +2,11 @@ import { authApi } from "@/api";
import { EUserRole, ITokenPair, StorageKey } from "@/shared";
import { isLoading, ResetAccount } from "@/store/account";
import { ResetTokens, SaveTokens } from "@/store/auth";
import { UnselectChat } from "@/store/chats";
import { Reset } from "@/store/shared";
import { simpleDispatch } from "@/store/store-helpers";
import { ClearFilter } from "@/store/task";
import { ClearContactsFilter, ClearUsersFilter } from "@/store/users";
import _ from "lodash";
import moment from "moment";
import {
@ -75,8 +78,10 @@ const autoAuth = async () => { @@ -75,8 +78,10 @@ const autoAuth = async () => {
if (!existTokens.refreshToken) throw new Error();
if (localStorage.getItem(StorageKey.RememberMe) === "true") {
await refreshSession(existTokens.refreshToken);
await loadDataAfterAuth();
} else if (moment(localStorage.getItem(StorageKey.ExpiryDate)) > moment()) {
await refreshSession(existTokens.refreshToken);
await loadDataAfterAuth();
}
await configsService.loadFilesLimitsConfig();
@ -97,6 +102,11 @@ const onLogout = async () => { @@ -97,6 +102,11 @@ const onLogout = async () => {
localStorage.removeItem(StorageKey.Path);
simpleDispatch(new ResetAccount());
simpleDispatch(new Reset());
simpleDispatch(new ClearUsersFilter());
simpleDispatch(new ClearFilter());
simpleDispatch(new ClearContactsFilter());
simpleDispatch(new UnselectChat());
simpleDispatch(new isLoading({ isLoading: false }));
};
const logout = async (refreshToken: string) => {
@ -107,9 +117,7 @@ const logout = async (refreshToken: string) => { @@ -107,9 +117,7 @@ const logout = async (refreshToken: string) => {
} catch (e) {
console.log("LOGOUT ERROR", e);
if (e.response.status === 401) {
// При оновленні сесії перед виходом з акаунту немає необхідності перезавантажувати дані акаунта,
// тому тут передається другий параметр = false
await refreshSession(refreshToken, false);
await refreshSession(refreshToken);
const { refreshToken: refresh } = await _getTokensFromStorage();
await logout(refresh);
} else await _resetTokens();
@ -127,9 +135,7 @@ const stopSession = async () => { @@ -127,9 +135,7 @@ const stopSession = async () => {
}
};
// Параметр reloadUserData визначає чи перезавантажувати дані акаунта після оновлення сесії
// У деяких випадках дана дія лишня
const refreshSession = async (refreshToken?: string, reloadUserData = true) => {
const refreshSession = async (refreshToken?: string) => {
let token = refreshToken;
if (!token) {
const existTokens = await _getTokensFromStorage();
@ -142,11 +148,10 @@ const refreshSession = async (refreshToken?: string, reloadUserData = true) => { @@ -142,11 +148,10 @@ const refreshSession = async (refreshToken?: string, reloadUserData = true) => {
refreshToken: token
});
await _saveTokens(data);
};
if (!reloadUserData) return;
const loadDataAfterAuth = async () => {
await accountService.getAccount();
if (_.isEmpty(store().getState()?.permissions?.availablePermissions))
await permissionsService.loadAvailablePermissions();

4
src/services/domain/chats.service.ts

@ -50,7 +50,9 @@ const fetchChatDetails = async ( @@ -50,7 +50,9 @@ const fetchChatDetails = async (
const deleteChatId = async (id: number): Promise<void> => {
try {
chatsApi.deleteChatByIdReq(id);
await chatsApi.deleteChatByIdReq(id);
appEvents.emit("onDeleteChatForMe", { chatId: id });
} catch (error) {
console.log("ERROR | DELETE CHAT: ", error);
}

4
src/services/domain/contact.service.ts

@ -8,10 +8,10 @@ const fetchContact = async (payload: number): Promise<IUser> => { @@ -8,10 +8,10 @@ const fetchContact = async (payload: number): Promise<IUser> => {
} catch (error) {
console.log("contact fetching error", error);
} finally {
console.log("contactinfo getted successfull");
// console.log("contactinfo getted successfull");
}
};
export const contactsService = {
fetchContact,
fetchContact
};

2
src/services/domain/users.service.ts

@ -20,7 +20,7 @@ const fetchUserStats = async (userId: number) => { @@ -20,7 +20,7 @@ const fetchUserStats = async (userId: number) => {
} catch (error) {
console.log("FETCH USER STATS ERROR", error);
} finally {
console.log("UserStats fetched");
// console.log("UserStats fetched");
}
};

1
src/services/system/real-time.service.ts

@ -93,6 +93,7 @@ export class SocketIo { @@ -93,6 +93,7 @@ export class SocketIo {
this._onSocketSendEvent("user/change-permissions");
this._onSocketSendEvent("chat/update-message");
this._onSocketSendEvent("version");
this._onSocketSendEvent("stopSessions");
this._on("error/join-user", async () => {

1
src/shared/enums/index.ts

@ -10,3 +10,4 @@ export * from "./chat-bg.enum"; @@ -10,3 +10,4 @@ export * from "./chat-bg.enum";
export * from "./factory.enums";
export * from "./push-notification.enum";
export * from "./file-type.enum";
export * from "./version.enum";

4
src/shared/enums/version.enum.ts

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
export enum EntityType {
Task = "t",
User = "u"
}

7
src/shared/events/index.ts

@ -1,12 +1,11 @@ @@ -1,12 +1,11 @@
import {
IChatMessage,
IComment,
IFile,
IMessage,
IPushNotification,
IPushNotification
} from "../interfaces";
import { Events } from "jet-tools";
import { ChatMemberRole } from "../enums";
import { ChatMemberRole, EntityType } from "../enums";
export type AppEvents = {
onDeleteChatForMe: { chatId: number };
@ -121,6 +120,8 @@ export type SocketEvents = { @@ -121,6 +120,8 @@ export type SocketEvents = {
notification: { notification: IPushNotification };
"chat/update-message": { message: IChatMessage };
version: { type: EntityType; entityId: number };
};
export const appEvents = new Events<AppEvents>();

11
src/shared/helpers/chat.helpers.ts

@ -49,12 +49,11 @@ export const getMessagePreviewText = (message: Record<string, any>) => { @@ -49,12 +49,11 @@ export const getMessagePreviewText = (message: Record<string, any>) => {
}
};
export const createFullName = (firstName: string, lastName: string) => {
const nameArr = [];
if (firstName) nameArr.push(firstName.trim());
if (lastName) nameArr.push(lastName.trim());
return nameArr.join(" ");
};
export const createFullName = (
firstName?: string,
middleName?: string,
lastName?: string
) => [lastName, firstName, middleName].filter(it => it).join(" ");
export const createFullRolePreviewText = (role: ChatMemberRole) => {
switch (role) {

2
src/shared/helpers/permissions.helpers.ts

@ -108,6 +108,8 @@ export const checkPermission = ( @@ -108,6 +108,8 @@ export const checkPermission = (
return true;
}
if (controller === "user" && target === user.id) return true;
if (_.isEmpty(permissions)) return false;
const targetPermissions = permissions[controller];

6
src/shared/interfaces/user.interfaces.ts

@ -46,6 +46,7 @@ export interface IShortUser { @@ -46,6 +46,7 @@ export interface IShortUser {
id: number;
firstName?: string;
fullName?: string;
middleName?: string;
lastName?: string;
dateOfBirth?: string;
avatarUrl?: string;
@ -85,7 +86,10 @@ export interface IUsersInfo { @@ -85,7 +86,10 @@ export interface IUsersInfo {
}
export interface IUserShortInfo
extends Pick<IUsersInfo, "userId" | "firstName" | "lastName"> {}
extends Pick<
IUsersInfo,
"userId" | "firstName" | "lastName" | "middleName"
> {}
export interface IUsersFilter {
isBlocked: boolean;

120
src/store/task/reducer.ts

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
import { ETaskStatus, ITaskFilter } from "@/shared";
import { createReducer } from "@bitalikrty/redux-create-reducer";
import _ from "lodash";
import moment from "moment";
import { TTaskActions } from "./types";
export const filterInitialState = {
@ -18,40 +16,10 @@ export const filterInitialState = { @@ -18,40 +16,10 @@ export const filterInitialState = {
};
export interface ITaskState {
filter: ITaskFilter;
// is_load: boolean,
// data: any[],
// show_modal: boolean,
// show_modal_view: boolean,
// item: any,
// totalCount: number,
// filter: {
// status: 'active',
// date: string
// },
// users: any[],
// factories: any[],
// task_types: any[],
// user_permissions: any,
// task_selected_ids: any[],
}
const initialState: ITaskState = {
filter: filterInitialState
// is_load: false,
// data: [],
// show_modal: false,
// show_modal_view: false,
// item: {},
// totalCount: 0,
// filter: {
// status: 'active',
// date: moment().format('YYYY-MM-DD')
// },
// users: [],
// factories: [],
// task_types: [],
// user_permissions: {},
// task_selected_ids: [],
};
export const taskReducer = createReducer<ITaskState, TTaskActions>(
@ -71,91 +39,3 @@ export const taskReducer = createReducer<ITaskState, TTaskActions>( @@ -71,91 +39,3 @@ export const taskReducer = createReducer<ITaskState, TTaskActions>(
}
}
);
// export default function (state = initialState, action) {
// let tmp_data = _.cloneDeep(state.data);
// let tmp_item = _.cloneDeep(state.item);
// switch (action.type) {
// case 'SET_TASK_SELECTED_IDS':
// return { ...state, task_selected_ids: action.data }
// case 'SET_TASK_IS_LOAD':
// return { ...state, is_load: action.status }
// case 'CLEAR_TASKS_DATA':
// return initialState;
// case 'SET_TASK_FILTER':
// return { ...state, filter: { ...action.filter, date: state.filter.date } };
// case 'SET_TASK_FILTER_DATE':
// return { ...state, filter: { ...state.filter, date: action.date } };
// case 'GET_TASKS':
// return {
// ...state,
// data: action.data,
// is_load: true,
// task_selected_ids: [],
// filter: { ...action.filter, date: state.filter.date },
// totalCount: action.data.length
// }
// case 'TASK_SHOW_MODAL':
// return { ...state, show_modal: action.status }
// case 'TASK_SHOW_MODAL_VIEW':
// return { ...state, show_modal_view: action.status }
// case 'TASK_SHOW_MODAL_PERFORMANCE':
// return { ...state, show_modal_performance: action.status }
// case 'TASK_SHOW_MODAL_REASSIGN':
// return { ...state, show_modal_reassign: action.status }
// case 'GET_TASK_USERS':
// return { ...state, users: action.data }
// case 'GET_TASK_USERS_PERMISSIONS':
// return { ...state, user_permissions: action.data }
// case 'GET_TASK_TYPES':
// return { ...state, task_types: action.data }
// case 'GET_TASK_FACTORIES':
// return { ...state, factories: action.data }
// case 'SET_TASK':
// return { ...state, item: action.item }
// case 'CREATE_TASK':
// return { ...state, data: [...state.data, action.data] }
// case 'UPDATE_TASK':
// return {
// ...state, data: tmp_data.map(item => {
// if (item.id == action.id) {
// return action.data;
// }
// return item;
// })
// }
// case 'DELETE_TASK':
// tmp_data = tmp_data.filter(item => {
// if (item.id == action.id) {
// return false;
// }
// return true;
// })
// return { ...state, data: tmp_data, task_selected_ids: [] }
// case 'SET_TASK_COMMENTS':
// return {
// ...state,
// item: { ...tmp_item, comments: action.data },
// data: tmp_data.map(item => {
// if (item.id == action.task_id) {
// return { ...item, comments: action.data };
// }
// return item;
// })
// };
// case 'SET_TASK_DOCUMENTS':
// return {
// ...state,
// item: { ...tmp_item, documents: action.data },
// data: tmp_data.map(item => {
// if (item.id == action.task_id) {
// return { ...item, documents: action.data };
// }
// return item;
// })
// };
// default:
// return state;
// }
// }

190
src/store/task/types.ts

@ -1,57 +1,4 @@ @@ -1,57 +1,4 @@
import { ITaskFilter } from "@/shared";
import { Action } from "redux";
export class ThemeColor implements Action {
readonly type = "THEME_COLOR";
constructor(
public readonly payload: {
themeColor: "theme-light" | "theme-dark";
}
) {}
}
export class isLoading {
readonly type = "IS_LOADING";
constructor(
public readonly payload: {
isLoading: boolean;
}
) {}
}
export class Reset {
readonly type = "RESET";
}
export class ChangeSidebarVisibility {
readonly type = "CHANGE_SIDEBAR_VISIBILITY";
}
export class SetTaskSelectedIds {
readonly type = "SET_TASK_SELECTED_IDS";
constructor(public readonly payload: any) {}
}
// case 'SET_TASK_SELECTED_IDS':
// return { ...state, task_selected_ids: action.data }
export class SetTaskIsLoad {
readonly type = "SET_TASK_IS_LOAD";
}
// case 'SET_TASK_IS_LOAD':
// return { ...state, is_load: action.status }
export class ClearTasksData {
readonly type = "CLEAR_TASKS_DATA";
}
// case 'CLEAR_TASKS_DATA':
// return initialState;
// export class SetTaskFilter {
// readonly type = 'SET_TASK_FILTER'
// }
// case 'SET_TASK_FILTER':
// return { ...state, filter: { ...action.filter, date: state.filter.date } };
export class SetTaskFilter {
readonly type = "SET_TASK_FILTER";
constructor(
@ -60,145 +7,8 @@ export class SetTaskFilter { @@ -60,145 +7,8 @@ export class SetTaskFilter {
}
) {}
}
export class SetTaskFilterDate {
readonly type = "SET_TASK_FILTER_DATE";
}
// case 'SET_TASK_FILTER_DATE':
// return { ...state, filter: { ...state.filter, date: action.date } };
export class GetTasks {
readonly type = "GET_TASKS";
}
// case 'GET_TASKS':
// return {
// ...state,
// data: action.data,
// is_load: true,
// task_selected_ids: [],
// filter: { ...action.filter, date: state.filter.date },
// totalCount: action.data.length
// }
export class TaskShowModal {
readonly type = "TASK_SHOW_MODAL";
}
// case 'TASK_SHOW_MODAL':
// return { ...state, show_modal: action.status }
export class TaskShowModalView {
readonly type = "TASK_SHOW_MODAL_VIEW";
}
// case 'TASK_SHOW_MODAL_VIEW':
// return { ...state, show_modal_view: action.status }
export class TaskShowModalPerformance {
readonly type = "TASK_SHOW_MODAL_PERFORMANCE";
}
// case 'TASK_SHOW_MODAL_PERFORMANCE':
// return { ...state, show_modal_performance: action.status }
export class TASK_SHOW_MODAL_REASSIGN {
readonly type = "TASK_SHOW_MODAL_REASSIGN";
}
// case 'TASK_SHOW_MODAL_REASSIGN':
// return { ...state, show_modal_reassign: action.status }
export class GET_TASK_USERS {
readonly type = "GET_TASK_USERS";
}
// case 'GET_TASK_USERS':
// return { ...state, users: action.data }
export class GET_TASK_USERS_PERMISSIONS {
readonly type = "GET_TASK_USERS_PERMISSIONS";
}
// case 'GET_TASK_USERS_PERMISSIONS':
// return { ...state, user_permissions: action.data }
export class GET_TASK_TYPES {
readonly type = "GET_TASK_TYPES";
}
// case 'GET_TASK_TYPES':
// return { ...state, task_types: action.data }
export class GET_TASK_FACTORIES {
readonly type = "GET_TASK_FACTORIES";
}
// case 'GET_TASK_FACTORIES':
// return { ...state, factories: action.data }
export class SET_TASK {
readonly type = "SET_TASK";
}
// case 'SET_TASK':
// return { ...state, item: action.item }
export class CREATE_TASK {
readonly type = "CREATE_TASK";
}
// case 'CREATE_TASK':
// return { ...state, data: [...state.data, action.data] }
export class UPDATE_TASK {
readonly type = "UPDATE_TASK";
}
// case 'UPDATE_TASK':
// return {
// ...state, data: tmp_data.map(item => {
// if (item.id == action.id) {
// return action.data;
// }
// return item;
// })
// }
export class DELETE_TASK {
readonly type = "DELETE_TASK";
}
// case 'DELETE_TASK':
// tmp_data = tmp_data.filter(item => {
// if (item.id == action.id) {
// return false;
// }
// return true;
// })
// return { ...state, data: tmp_data, task_selected_ids: [] }
export class SET_TASK_COMMENTS {
readonly type = "SET_TASK_COMMENTS";
}
// case 'SET_TASK_COMMENTS':
// return {
// ...state,
// item: { ...tmp_item, comments: action.data },
// data: tmp_data.map(item => {
// if (item.id == action.task_id) {
// return { ...item, comments: action.data };
// }
// return item;
// })
// };
export class SET_TASK_DOCUMENTS {
readonly type = "SET_TASK_DOCUMENTS";
}
// case 'SET_TASK_DOCUMENTS':
// return {
// ...state,
// item: { ...tmp_item, documents: action.data },
// data: tmp_data.map(item => {
// if (item.id == action.task_id) {
// return { ...item, documents: action.data };
// }
// return item;
// })
// };
export class ClearFilter {
readonly type = "CLEAR_FILTER";
}
// export type TTaskActions = ThemeColor | isLoading | Reset | ChangeSidebarVisibility | ChangeMobileSidebarVisibility
export type TTaskActions = SetTaskFilter | ClearFilter;

Loading…
Cancel
Save