Skip to content

Commit 81aee2a

Browse files
m0ksemraichev-dimadependabot[bot]
authored
chore: sync develop with master (#1070)
* feat: connect Users to the backend (cherry picked from commit 45956f1) * feat: connect Projects to the backend (#1063) (cherry picked from commit 5554ae4) * fix: move sorting/pagination to hooks (#1064) (cherry picked from commit e83ed7b) * feat: implement files uploading integration (#1065) (cherry picked from commit 42fa1cb) * fix(EditUserForm): filter out removed projects (cherry picked from commit b52bd07) * fix(UserAvatar): make sure avatar is not null (cherry picked from commit 1b931db) * chore: sync master with develop (#1069) * chore(deps): bump ws from 6.2.2 to 6.2.3 (#1040) Bumps [ws](https://github.com/websockets/ws) from 6.2.2 to 6.2.3. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](websockets/ws@6.2.2...6.2.3) --- updated-dependencies: - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump braces from 3.0.2 to 3.0.3 (#1039) Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](micromatch/braces@3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump ejs from 3.1.9 to 3.1.10 (#1034) Bumps [ejs](https://github.com/mde/ejs) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/mde/ejs/releases) - [Commits](mde/ejs@v3.1.9...v3.1.10) --- updated-dependencies: - dependency-name: ejs dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump tar from 6.2.0 to 6.2.1 (#1033) Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1. - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](isaacs/node-tar@v6.2.0...v6.2.1) --- updated-dependencies: - dependency-name: tar dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump express from 4.18.2 to 4.19.2 (#1031) Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](expressjs/express@4.18.2...4.19.2) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump express from 4.19.2 to 4.21.1 (#1057) Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.21.1. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](expressjs/express@4.19.2...4.21.1) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump pug from 3.0.2 to 3.0.3 (#1058) Bumps [pug](https://github.com/pugjs/pug) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/pugjs/pug/releases) - [Commits](https://github.com/pugjs/pug/compare/[email protected]@3.0.3) --- updated-dependencies: - dependency-name: pug dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: connect Users to the backend * feat: connect Projects to the backend (#1063) * fix: move sorting/pagination to hooks (#1064) * feat: implement files uploading integration (#1065) * fix(EditUserForm): filter out removed projects * fix(UserAvatar): make sure avatar is not null * Revert "fix(UserAvatar): make sure avatar is not null" This reverts commit 1b931db. * Revert "fix(EditUserForm): filter out removed projects" This reverts commit b52bd07. * Revert "feat: implement files uploading integration (#1065)" This reverts commit 42fa1cb. * Revert "fix: move sorting/pagination to hooks (#1064)" This reverts commit e83ed7b. * Revert "feat: connect Projects to the backend (#1063)" This reverts commit 5554ae4. * Revert "feat: connect Users to the backend" This reverts commit 45956f1. --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: raichev-dima <[email protected]> --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: raichev-dima <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 9fb9949 commit 81aee2a

23 files changed

+501
-323
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ VITE_APP_INCLUDE_DEMOS=
55
VITE_APP_ROUTER_MODE_HISTORY=
66

77
VITE_APP_BUILD_VERSION=
8+
9+
VITE_API_BASE_URL=

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules
1111
dist
1212
dist-ssr
1313
*.local
14+
.env
1415

1516
# Editor directories and files
1617
.vscode/*
@@ -25,3 +26,4 @@ dist-ssr
2526

2627
# Local Netlify folder
2728
.netlify
29+

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"register-service-worker": "^1.7.1",
3636
"sass": "^1.69.5",
3737
"serve": "^14.2.1",
38+
"uuid": "^11.0.3",
3839
"vue": "3.5.8",
3940
"vue-chartjs": "^5.3.0",
4041
"vue-i18n": "^9.6.2",

src/data/pages/projects.ts

+17-76
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,43 @@
1-
import { sleep } from '../../services/utils'
2-
import projectsDb from './projects-db.json'
3-
import usersDb from './users-db.json'
1+
import api from '../../services/api'
2+
import { Project } from '../../pages/projects/types'
43

5-
// Simulate API calls
64
export type Pagination = {
75
page: number
86
perPage: number
97
total: number
108
}
119

1210
export type Sorting = {
13-
sortBy: keyof (typeof projectsDb)[number] | undefined
11+
sortBy: 'project_owner' | 'team' | 'created_at'
1412
sortingOrder: 'asc' | 'desc' | null
1513
}
1614

17-
const getSortItem = (obj: any, sortBy: keyof (typeof projectsDb)[number]) => {
18-
if (sortBy === 'project_owner') {
19-
return obj.project_owner.fullname
20-
}
21-
22-
if (sortBy === 'team') {
23-
return obj.team.map((user: any) => user.fullname).join(', ')
24-
}
25-
26-
if (sortBy === 'creation_date') {
27-
return new Date(obj[sortBy])
28-
}
29-
30-
return obj[sortBy]
31-
}
32-
33-
export const getProjects = async (options: Sorting & Pagination) => {
34-
await sleep(1000)
35-
36-
const projects = projectsDb.map((project) => ({
37-
...project,
38-
project_owner: usersDb.find((user) => user.id === project.project_owner)! as (typeof usersDb)[number],
39-
team: usersDb.filter((user) => project.team.includes(user.id)) as (typeof usersDb)[number][],
40-
}))
41-
42-
if (options.sortBy && options.sortingOrder) {
43-
projects.sort((a, b) => {
44-
a = getSortItem(a, options.sortBy!)
45-
b = getSortItem(b, options.sortBy!)
46-
if (a < b) {
47-
return options.sortingOrder === 'asc' ? -1 : 1
48-
}
49-
if (a > b) {
50-
return options.sortingOrder === 'asc' ? 1 : -1
51-
}
52-
return 0
53-
})
54-
}
55-
56-
const normalizedProjects = projects.slice((options.page - 1) * options.perPage, options.page * options.perPage)
15+
export const getProjects = async (options: Partial<Sorting> & Pagination) => {
16+
const projects: Project[] = await fetch(api.allProjects()).then((r) => r.json())
5717

5818
return {
59-
data: normalizedProjects,
19+
data: projects,
6020
pagination: {
6121
page: options.page,
6222
perPage: options.perPage,
63-
total: projectsDb.length,
23+
total: projects.length,
6424
},
6525
}
6626
}
6727

68-
export const addProject = async (project: Omit<(typeof projectsDb)[number], 'id' | 'creation_date'>) => {
69-
await sleep(1000)
70-
71-
const newProject = {
72-
...project,
73-
id: projectsDb.length + 1,
74-
creation_date: new Date().toLocaleDateString('gb', { day: 'numeric', month: 'short', year: 'numeric' }),
75-
}
28+
export const addProject = async (project: Omit<Project, 'id' | 'created_at'>) => {
29+
const headers = new Headers()
30+
headers.append('Content-Type', 'application/json')
7631

77-
projectsDb.push(newProject)
78-
79-
return {
80-
...newProject,
81-
project_owner: usersDb.find((user) => user.id === project.project_owner)! as (typeof usersDb)[number],
82-
team: usersDb.filter((user) => project.team.includes(user.id)) as (typeof usersDb)[number][],
83-
}
32+
return fetch(api.allProjects(), { method: 'POST', body: JSON.stringify(project), headers }).then((r) => r.json())
8433
}
8534

86-
export const updateProject = async (project: (typeof projectsDb)[number]) => {
87-
await sleep(1000)
88-
89-
const index = projectsDb.findIndex((p) => p.id === project.id)
90-
projectsDb[index] = project
91-
92-
return project
35+
export const updateProject = async (project: Omit<Project, 'created_at'>) => {
36+
const headers = new Headers()
37+
headers.append('Content-Type', 'application/json')
38+
return fetch(api.project(project.id), { method: 'PUT', body: JSON.stringify(project), headers }).then((r) => r.json())
9339
}
9440

95-
export const removeProject = async (project: (typeof projectsDb)[number]) => {
96-
await sleep(1000)
97-
98-
const index = projectsDb.findIndex((p) => p.id === project.id)
99-
projectsDb.splice(index, 1)
100-
101-
return project
41+
export const removeProject = async (project: Project) => {
42+
return fetch(api.project(project.id), { method: 'DELETE' })
10243
}

src/data/pages/users.ts

+34-58
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
1-
import { sleep } from '../../services/utils'
2-
import { User } from './../../pages/users/types'
3-
import usersDb from './users-db.json'
4-
import projectsDb from './projects-db.json'
5-
import { Project } from '../../pages/projects/types'
6-
7-
export const users = usersDb as User[]
8-
9-
const getUserProjects = (userId: number | string) => {
10-
return projectsDb
11-
.filter((project) => project.team.includes(Number(userId)))
12-
.map((project) => ({
13-
...project,
14-
project_owner: users.find((user) => user.id === project.project_owner)!,
15-
team: project.team.map((userId) => users.find((user) => user.id === userId)!),
16-
status: project.status as Project['status'],
17-
}))
18-
}
19-
20-
// Simulate API calls
1+
import { User } from '../../pages/users/types'
2+
import api from '../../services/api'
213

224
export type Pagination = {
235
page: number
@@ -35,44 +17,19 @@ export type Filters = {
3517
search: string
3618
}
3719

38-
const getSortItem = (obj: any, sortBy: string) => {
39-
if (sortBy === 'projects') {
40-
return obj.projects.map((project: any) => project.project_name).join(', ')
41-
}
42-
43-
return obj[sortBy]
44-
}
45-
4620
export const getUsers = async (filters: Partial<Filters & Pagination & Sorting>) => {
47-
await sleep(1000)
48-
const { isActive, search, sortBy, sortingOrder } = filters
49-
let filteredUsers = users
21+
const { isActive, search } = filters
22+
let filteredUsers: User[] = await fetch(api.allUsers()).then((r) => r.json())
5023

5124
filteredUsers = filteredUsers.filter((user) => user.active === isActive)
5225

5326
if (search) {
5427
filteredUsers = filteredUsers.filter((user) => user.fullname.toLowerCase().includes(search.toLowerCase()))
5528
}
5629

57-
filteredUsers = filteredUsers.map((user) => ({ ...user, projects: getUserProjects(user.id) }))
58-
59-
if (sortBy && sortingOrder) {
60-
filteredUsers = filteredUsers.sort((a, b) => {
61-
const first = getSortItem(a, sortBy)
62-
const second = getSortItem(b, sortBy)
63-
if (first > second) {
64-
return sortingOrder === 'asc' ? 1 : -1
65-
}
66-
if (first < second) {
67-
return sortingOrder === 'asc' ? -1 : 1
68-
}
69-
return 0
70-
})
71-
}
72-
7330
const { page = 1, perPage = 10 } = filters || {}
7431
return {
75-
data: filteredUsers.slice((page - 1) * perPage, page * perPage),
32+
data: filteredUsers,
7633
pagination: {
7734
page,
7835
perPage,
@@ -82,20 +39,39 @@ export const getUsers = async (filters: Partial<Filters & Pagination & Sorting>)
8239
}
8340

8441
export const addUser = async (user: User) => {
85-
await sleep(1000)
86-
users.unshift(user)
42+
const headers = new Headers()
43+
headers.append('Content-Type', 'application/json')
44+
45+
const result = await fetch(api.allUsers(), { method: 'POST', body: JSON.stringify(user), headers }).then((r) =>
46+
r.json(),
47+
)
48+
49+
if (!result.error) {
50+
return result
51+
}
52+
53+
throw new Error(result.error)
8754
}
8855

8956
export const updateUser = async (user: User) => {
90-
await sleep(1000)
91-
const index = users.findIndex((u) => u.id === user.id)
92-
users[index] = user
57+
const headers = new Headers()
58+
headers.append('Content-Type', 'application/json')
59+
60+
const result = await fetch(api.user(user.id), { method: 'PUT', body: JSON.stringify(user), headers }).then((r) =>
61+
r.json(),
62+
)
63+
64+
if (!result.error) {
65+
return result
66+
}
67+
68+
throw new Error(result.error)
9369
}
9470

9571
export const removeUser = async (user: User) => {
96-
await sleep(1000)
97-
users.splice(
98-
users.findIndex((u) => u.id === user.id),
99-
1,
100-
)
72+
return fetch(api.user(user.id), { method: 'DELETE' })
73+
}
74+
75+
export const uploadAvatar = async (body: FormData) => {
76+
return fetch(api.avatars(), { method: 'POST', body, redirect: 'follow' }).then((r) => r.json())
10177
}

src/pages/admin/dashboard/cards/ProjectTable.vue

+9-20
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<script setup lang="ts">
22
import { defineVaDataTableColumns } from 'vuestic-ui'
3-
import { Project } from '../../../projects/types'
43
import UserAvatar from '../../../users/widgets/UserAvatar.vue'
54
import ProjectStatusBadge from '../../../projects/components/ProjectStatusBadge.vue'
65
import { useProjects } from '../../../projects/composables/useProjects'
76
import { Pagination } from '../../../../data/pages/projects'
87
import { ref } from 'vue'
8+
import { useProjectUsers } from '../../../projects/composables/useProjectUsers'
99
1010
const columns = defineVaDataTableColumns([
1111
{ label: 'Name', key: 'project_name', sortable: true },
@@ -18,11 +18,7 @@ const { projects, isLoading, sorting } = useProjects({
1818
pagination,
1919
})
2020
21-
const avatarColor = (userName: string) => {
22-
const colors = ['primary', '#FFD43A', '#ADFF00', '#262824', 'danger']
23-
const index = userName.charCodeAt(0) % colors.length
24-
return colors[index]
25-
}
21+
const { getTeamOptions, getUserById } = useProjectUsers()
2622
</script>
2723

2824
<template>
@@ -47,23 +43,16 @@ const avatarColor = (userName: string) => {
4743
</template>
4844
<template #cell(project_owner)="{ rowData }">
4945
<div class="flex items-center gap-2 ellipsis max-w-[230px]">
50-
<UserAvatar :user="rowData.project_owner" size="small" />
51-
{{ rowData.project_owner.fullname }}
46+
<UserAvatar
47+
v-if="getUserById(rowData.project_owner)"
48+
:user="getUserById(rowData.project_owner)!"
49+
size="small"
50+
/>
51+
{{ getUserById(rowData.project_owner)?.fullname }}
5252
</div>
5353
</template>
5454
<template #cell(team)="{ rowData: project }">
55-
<VaAvatarGroup
56-
size="small"
57-
:options="
58-
(project as Project).team.map((user) => ({
59-
label: user.fullname,
60-
src: user.avatar,
61-
fallbackText: user.fullname[0],
62-
color: avatarColor(user.fullname),
63-
}))
64-
"
65-
:max="2"
66-
/>
55+
<VaAvatarGroup size="small" :options="getTeamOptions(project.team)" :max="2" />
6756
</template>
6857
<template #cell(status)="{ rowData: project }">
6958
<ProjectStatusBadge :status="project.status" />

src/pages/projects/ProjectsPage.vue

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
<script setup lang="ts">
2-
import { ref } from 'vue'
2+
import { ref, provide } from 'vue'
33
import { useLocalStorage } from '@vueuse/core'
44
import { useProjects } from './composables/useProjects'
55
import ProjectCards from './widgets/ProjectCards.vue'
66
import ProjectTable from './widgets/ProjectsTable.vue'
77
import EditProjectForm from './widgets/EditProjectForm.vue'
88
import { Project } from './types'
99
import { useModal, useToast } from 'vuestic-ui'
10+
import { useProjectUsers } from './composables/useProjectUsers'
1011
1112
const doShowAsCards = useLocalStorage('projects-view', true)
1213
1314
const { projects, update, add, isLoading, remove, pagination, sorting } = useProjects()
1415
16+
const { users, getTeamOptions, getUserById } = useProjectUsers()
17+
18+
provide('ProjectsPage', {
19+
users,
20+
getTeamOptions,
21+
getUserById,
22+
})
23+
1524
const projectToEdit = ref<Project | null>(null)
1625
const doShowProjectFormModal = ref(false)
1726
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { useUsers } from '../../users/composables/useUsers'
2+
import { Project } from '../types'
3+
4+
export function useProjectUsers() {
5+
const { users } = useUsers()
6+
7+
const getUserById = (userId: string) => {
8+
return users.value.find(({ id }) => userId === id)
9+
}
10+
11+
const avatarColor = (userName: string) => {
12+
const colors = ['primary', '#FFD43A', '#ADFF00', '#262824', 'danger']
13+
const index = userName.charCodeAt(0) % colors.length
14+
return colors[index]
15+
}
16+
17+
const getTeamOptions = (team: Project['team']) => {
18+
return team.reduce(
19+
(acc, userId) => {
20+
const user = getUserById(userId)
21+
22+
if (user) {
23+
acc.push({
24+
label: user.fullname,
25+
src: user.avatar,
26+
fallbackText: user.fullname[0],
27+
color: avatarColor(user.fullname),
28+
})
29+
}
30+
31+
return acc
32+
},
33+
[] as Record<string, string>[],
34+
)
35+
}
36+
37+
return {
38+
users,
39+
getUserById,
40+
getTeamOptions,
41+
}
42+
}

0 commit comments

Comments
 (0)