diff --git a/.env.example b/.env.example index 854aae654..c61cc7529 100644 --- a/.env.example +++ b/.env.example @@ -5,5 +5,3 @@ VITE_APP_INCLUDE_DEMOS= VITE_APP_ROUTER_MODE_HISTORY= VITE_APP_BUILD_VERSION= - -VITE_API_BASE_URL= diff --git a/.gitignore b/.gitignore index f9d0c5bb8..c3bb0dbc3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ node_modules dist dist-ssr *.local -.env # Editor directories and files .vscode/* @@ -26,4 +25,3 @@ dist-ssr # Local Netlify folder .netlify - diff --git a/src/data/pages/users.ts b/src/data/pages/users.ts index a8e9d5134..80285863f 100644 --- a/src/data/pages/users.ts +++ b/src/data/pages/users.ts @@ -1,5 +1,23 @@ -import { User } from '../../pages/users/types' -import api from '../../services/api' +import { sleep } from '../../services/utils' +import { User } from './../../pages/users/types' +import usersDb from './users-db.json' +import projectsDb from './projects-db.json' +import { Project } from '../../pages/projects/types' + +export const users = usersDb as User[] + +const getUserProjects = (userId: number | string) => { + return projectsDb + .filter((project) => project.team.includes(Number(userId))) + .map((project) => ({ + ...project, + project_owner: users.find((user) => user.id === project.project_owner)!, + team: project.team.map((userId) => users.find((user) => user.id === userId)!), + status: project.status as Project['status'], + })) +} + +// Simulate API calls export type Pagination = { page: number @@ -19,22 +37,25 @@ export type Filters = { const getSortItem = (obj: any, sortBy: string) => { if (sortBy === 'projects') { - return obj.projects.map((project: any) => project).join(', ') + return obj.projects.map((project: any) => project.project_name).join(', ') } return obj[sortBy] } export const getUsers = async (filters: Partial) => { + await sleep(1000) const { isActive, search, sortBy, sortingOrder } = filters - let filteredUsers: User[] = await fetch(api.getAllUsers()).then((r) => r.json()) + let filteredUsers = users - filteredUsers = filteredUsers.filter((user) => user.isActive === isActive) + filteredUsers = filteredUsers.filter((user) => user.active === isActive) if (search) { - filteredUsers = filteredUsers.filter((user) => user.fullName.toLowerCase().includes(search.toLowerCase())) + filteredUsers = filteredUsers.filter((user) => user.fullname.toLowerCase().includes(search.toLowerCase())) } + filteredUsers = filteredUsers.map((user) => ({ ...user, projects: getUserProjects(user.id) })) + if (sortBy && sortingOrder) { filteredUsers = filteredUsers.sort((a, b) => { const first = getSortItem(a, sortBy) @@ -61,18 +82,20 @@ export const getUsers = async (filters: Partial) } export const addUser = async (user: User) => { - const headers = new Headers() - headers.append('Content-Type', 'application/json') - - return fetch(api.getAllUsers(), { method: 'POST', body: JSON.stringify(user), headers }) + await sleep(1000) + users.unshift(user) } export const updateUser = async (user: User) => { - const headers = new Headers() - headers.append('Content-Type', 'application/json') - return fetch(api.getUser(user.id), { method: 'PUT', body: JSON.stringify(user), headers }) + await sleep(1000) + const index = users.findIndex((u) => u.id === user.id) + users[index] = user } export const removeUser = async (user: User) => { - return fetch(api.getUser(user.id), { method: 'DELETE' }) + await sleep(1000) + users.splice( + users.findIndex((u) => u.id === user.id), + 1, + ) } diff --git a/src/pages/users/UsersPage.vue b/src/pages/users/UsersPage.vue index ed5e55d20..56cb3c061 100644 --- a/src/pages/users/UsersPage.vue +++ b/src/pages/users/UsersPage.vue @@ -28,13 +28,13 @@ const onUserSaved = async (user: User) => { if (userToEdit.value) { await usersApi.update(user) notify({ - message: `${user.fullName} has been updated`, + message: `${user.fullname} has been updated`, color: 'success', }) } else { - await usersApi.add(user) + usersApi.add(user) notify({ - message: `${user.fullName} has been created`, + message: `${user.fullname} has been created`, color: 'success', }) } @@ -43,7 +43,7 @@ const onUserSaved = async (user: User) => { const onUserDelete = async (user: User) => { await usersApi.remove(user) notify({ - message: `${user.fullName} has been deleted`, + message: `${user.fullname} has been deleted`, color: 'success', }) } diff --git a/src/pages/users/composables/useUsers.ts b/src/pages/users/composables/useUsers.ts index bab35c89e..1d051f97d 100644 --- a/src/pages/users/composables/useUsers.ts +++ b/src/pages/users/composables/useUsers.ts @@ -4,7 +4,7 @@ import { User } from '../types' import { watchIgnorable } from '@vueuse/core' const makePaginationRef = () => ref({ page: 1, perPage: 10, total: 0 }) -const makeSortingRef = () => ref({ sortBy: 'fullName', sortingOrder: null }) +const makeSortingRef = () => ref({ sortBy: 'fullname', sortingOrder: null }) const makeFiltersRef = () => ref>({ isActive: true, search: '' }) export const useUsers = (options?: { diff --git a/src/pages/users/types.ts b/src/pages/users/types.ts index 882efbb5b..3b167c85e 100644 --- a/src/pages/users/types.ts +++ b/src/pages/users/types.ts @@ -1,15 +1,16 @@ -export type UserRole = 'ADMIN' | 'USER' | 'OWNER' +import { Project } from '../projects/types' -export type UUID = `${string}-${string}-${string}-${string}-${string}` +export type UserRole = 'admin' | 'user' | 'owner' -export type User = { - id: UUID - fullName: string +export type BaseUser = { + id: number + fullname: string email: string username: string role: UserRole avatar: string - projects: string[] notes: string - isActive: boolean + active: boolean } + +export type User = BaseUser & { projects: Project[] } diff --git a/src/pages/users/widgets/EditUserForm.vue b/src/pages/users/widgets/EditUserForm.vue index d5ed5bd4d..3b5713d31 100644 --- a/src/pages/users/widgets/EditUserForm.vue +++ b/src/pages/users/widgets/EditUserForm.vue @@ -17,18 +17,19 @@ const props = defineProps({ }, }) -const defaultNewUser: Omit = { +const defaultNewUser: User = { + id: -1, avatar: '', - fullName: '', - role: 'USER', + fullname: '', + role: 'user', username: '', notes: '', email: '', - isActive: true, + active: true, projects: [], } -const newUser = ref({ ...defaultNewUser } as User) +const newUser = ref({ ...defaultNewUser }) const isFormHasUnsavedChanges = computed(() => { return Object.keys(newUser.value).some((key) => { @@ -36,9 +37,7 @@ const isFormHasUnsavedChanges = computed(() => { return false } - return ( - newUser.value[key as keyof Omit] !== (props.user ?? defaultNewUser)?.[key as keyof Omit] - ) + return newUser.value[key as keyof User] !== (props.user ?? defaultNewUser)?.[key as keyof User] }) }) @@ -81,10 +80,10 @@ const onSave = () => { } } -const roleSelectOptions: { text: Capitalize>; value: UserRole }[] = [ - { text: 'Admin', value: 'ADMIN' }, - { text: 'User', value: 'USER' }, - { text: 'Owner', value: 'OWNER' }, +const roleSelectOptions: { text: Capitalize; value: UserRole }[] = [ + { text: 'Admin', value: 'admin' }, + { text: 'User', value: 'user' }, + { text: 'Owner', value: 'owner' }, ] const { projects } = useProjects({ pagination: ref({ page: 1, perPage: 9999, total: 10 }) }) @@ -113,11 +112,11 @@ const { projects } = useProjects({ pagination: ref({ page: 1, perPage: 9999, tot
@@ -161,7 +162,7 @@ const { projects } = useProjects({ pagination: ref({ page: 1, perPage: 9999, tot
- +
diff --git a/src/pages/users/widgets/UserAvatar.vue b/src/pages/users/widgets/UserAvatar.vue index b64f5f21c..5c8a7b5a6 100644 --- a/src/pages/users/widgets/UserAvatar.vue +++ b/src/pages/users/widgets/UserAvatar.vue @@ -28,7 +28,7 @@ const isUrl = (avatar: string) => { diff --git a/src/pages/users/widgets/UsersTable.vue b/src/pages/users/widgets/UsersTable.vue index 22ff8a3f1..701e498fc 100644 --- a/src/pages/users/widgets/UsersTable.vue +++ b/src/pages/users/widgets/UsersTable.vue @@ -8,7 +8,7 @@ import { useVModel } from '@vueuse/core' import { Project } from '../../projects/types' const columns = defineVaDataTableColumns([ - { label: 'Full Name', key: 'fullName', sortable: true }, + { label: 'Full Name', key: 'fullname', sortable: true }, { label: 'Email', key: 'email', sortable: true }, { label: 'Username', key: 'username', sortable: true }, { label: 'Role', key: 'role', sortable: true }, @@ -24,7 +24,7 @@ const props = defineProps({ loading: { type: Boolean, default: false }, pagination: { type: Object as PropType, required: true }, sortBy: { type: String as PropType, required: true }, - sortingOrder: { type: String as PropType, default: null }, + sortingOrder: { type: String as PropType, required: true }, }) const emit = defineEmits<{ @@ -39,9 +39,9 @@ const sortByVModel = useVModel(props, 'sortBy', emit) const sortingOrderVModel = useVModel(props, 'sortingOrder', emit) const roleColors: Record = { - ADMIN: 'danger', - USER: 'background-element', - OWNER: 'warning', + admin: 'danger', + user: 'background-element', + owner: 'warning', } const totalPages = computed(() => Math.ceil(props.pagination.total / props.pagination.perPage)) @@ -51,7 +51,7 @@ const { confirm } = useModal() const onUserDelete = async (user: User) => { const agreed = await confirm({ title: 'Delete user', - message: `Are you sure you want to delete ${user.fullName}?`, + message: `Are you sure you want to delete ${user.fullname}?`, okText: 'Delete', cancelText: 'Cancel', size: 'small', @@ -66,13 +66,13 @@ const onUserDelete = async (user: User) => { const formatProjectNames = (projects: Project[]) => { if (projects.length === 0) return 'No projects' if (projects.length <= 2) { - return projects.map((project) => project).join(', ') + return projects.map((project) => project.project_name).join(', ') } return ( projects .slice(0, 2) - .map((project) => project) + .map((project) => project.project_name) .join(', ') + ' + ' + (projects.length - 2) + @@ -89,10 +89,10 @@ const formatProjectNames = (projects: Project[]) => { :items="users" :loading="$props.loading" > -