Skip to content

Commit

Permalink
chore: sync develop with master (#1070)
Browse files Browse the repository at this point in the history
* 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] <support@github.com>
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] <support@github.com>
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] <support@github.com>
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] <support@github.com>
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] <support@github.com>
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] <support@github.com>
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/pug@3.0.2...pug@3.0.3)

---
updated-dependencies:
- dependency-name: pug
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
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] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: raichev-dima <raichevdp@gmail.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: raichev-dima <raichevdp@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 5, 2025
1 parent 524f96f commit 229daa6
Show file tree
Hide file tree
Showing 23 changed files with 501 additions and 323 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ VITE_APP_INCLUDE_DEMOS=
VITE_APP_ROUTER_MODE_HISTORY=

VITE_APP_BUILD_VERSION=

VITE_API_BASE_URL=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
.env

# Editor directories and files
.vscode/*
Expand All @@ -25,3 +26,4 @@ dist-ssr

# Local Netlify folder
.netlify

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"register-service-worker": "^1.7.1",
"sass": "^1.69.5",
"serve": "^14.2.1",
"uuid": "^11.0.3",
"vue": "3.5.8",
"vue-chartjs": "^5.3.0",
"vue-i18n": "^9.6.2",
Expand Down
93 changes: 17 additions & 76 deletions src/data/pages/projects.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,43 @@
import { sleep } from '../../services/utils'
import projectsDb from './projects-db.json'
import usersDb from './users-db.json'
import api from '../../services/api'
import { Project } from '../../pages/projects/types'

// Simulate API calls
export type Pagination = {
page: number
perPage: number
total: number
}

export type Sorting = {
sortBy: keyof (typeof projectsDb)[number] | undefined
sortBy: 'project_owner' | 'team' | 'created_at'
sortingOrder: 'asc' | 'desc' | null
}

const getSortItem = (obj: any, sortBy: keyof (typeof projectsDb)[number]) => {
if (sortBy === 'project_owner') {
return obj.project_owner.fullname
}

if (sortBy === 'team') {
return obj.team.map((user: any) => user.fullname).join(', ')
}

if (sortBy === 'creation_date') {
return new Date(obj[sortBy])
}

return obj[sortBy]
}

export const getProjects = async (options: Sorting & Pagination) => {
await sleep(1000)

const projects = projectsDb.map((project) => ({
...project,
project_owner: usersDb.find((user) => user.id === project.project_owner)! as (typeof usersDb)[number],
team: usersDb.filter((user) => project.team.includes(user.id)) as (typeof usersDb)[number][],
}))

if (options.sortBy && options.sortingOrder) {
projects.sort((a, b) => {
a = getSortItem(a, options.sortBy!)
b = getSortItem(b, options.sortBy!)
if (a < b) {
return options.sortingOrder === 'asc' ? -1 : 1
}
if (a > b) {
return options.sortingOrder === 'asc' ? 1 : -1
}
return 0
})
}

const normalizedProjects = projects.slice((options.page - 1) * options.perPage, options.page * options.perPage)
export const getProjects = async (options: Partial<Sorting> & Pagination) => {
const projects: Project[] = await fetch(api.allProjects()).then((r) => r.json())

return {
data: normalizedProjects,
data: projects,
pagination: {
page: options.page,
perPage: options.perPage,
total: projectsDb.length,
total: projects.length,
},
}
}

export const addProject = async (project: Omit<(typeof projectsDb)[number], 'id' | 'creation_date'>) => {
await sleep(1000)

const newProject = {
...project,
id: projectsDb.length + 1,
creation_date: new Date().toLocaleDateString('gb', { day: 'numeric', month: 'short', year: 'numeric' }),
}
export const addProject = async (project: Omit<Project, 'id' | 'created_at'>) => {
const headers = new Headers()
headers.append('Content-Type', 'application/json')

projectsDb.push(newProject)

return {
...newProject,
project_owner: usersDb.find((user) => user.id === project.project_owner)! as (typeof usersDb)[number],
team: usersDb.filter((user) => project.team.includes(user.id)) as (typeof usersDb)[number][],
}
return fetch(api.allProjects(), { method: 'POST', body: JSON.stringify(project), headers }).then((r) => r.json())
}

export const updateProject = async (project: (typeof projectsDb)[number]) => {
await sleep(1000)

const index = projectsDb.findIndex((p) => p.id === project.id)
projectsDb[index] = project

return project
export const updateProject = async (project: Omit<Project, 'created_at'>) => {
const headers = new Headers()
headers.append('Content-Type', 'application/json')
return fetch(api.project(project.id), { method: 'PUT', body: JSON.stringify(project), headers }).then((r) => r.json())
}

export const removeProject = async (project: (typeof projectsDb)[number]) => {
await sleep(1000)

const index = projectsDb.findIndex((p) => p.id === project.id)
projectsDb.splice(index, 1)

return project
export const removeProject = async (project: Project) => {
return fetch(api.project(project.id), { method: 'DELETE' })
}
92 changes: 34 additions & 58 deletions src/data/pages/users.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
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
import { User } from '../../pages/users/types'
import api from '../../services/api'

export type Pagination = {
page: number
Expand All @@ -35,44 +17,19 @@ export type Filters = {
search: string
}

const getSortItem = (obj: any, sortBy: string) => {
if (sortBy === 'projects') {
return obj.projects.map((project: any) => project.project_name).join(', ')
}

return obj[sortBy]
}

export const getUsers = async (filters: Partial<Filters & Pagination & Sorting>) => {
await sleep(1000)
const { isActive, search, sortBy, sortingOrder } = filters
let filteredUsers = users
const { isActive, search } = filters
let filteredUsers: User[] = await fetch(api.allUsers()).then((r) => r.json())

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

if (search) {
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)
const second = getSortItem(b, sortBy)
if (first > second) {
return sortingOrder === 'asc' ? 1 : -1
}
if (first < second) {
return sortingOrder === 'asc' ? -1 : 1
}
return 0
})
}

const { page = 1, perPage = 10 } = filters || {}
return {
data: filteredUsers.slice((page - 1) * perPage, page * perPage),
data: filteredUsers,
pagination: {
page,
perPage,
Expand All @@ -82,20 +39,39 @@ export const getUsers = async (filters: Partial<Filters & Pagination & Sorting>)
}

export const addUser = async (user: User) => {
await sleep(1000)
users.unshift(user)
const headers = new Headers()
headers.append('Content-Type', 'application/json')

const result = await fetch(api.allUsers(), { method: 'POST', body: JSON.stringify(user), headers }).then((r) =>
r.json(),
)

if (!result.error) {
return result
}

throw new Error(result.error)
}

export const updateUser = async (user: User) => {
await sleep(1000)
const index = users.findIndex((u) => u.id === user.id)
users[index] = user
const headers = new Headers()
headers.append('Content-Type', 'application/json')

const result = await fetch(api.user(user.id), { method: 'PUT', body: JSON.stringify(user), headers }).then((r) =>
r.json(),
)

if (!result.error) {
return result
}

throw new Error(result.error)
}

export const removeUser = async (user: User) => {
await sleep(1000)
users.splice(
users.findIndex((u) => u.id === user.id),
1,
)
return fetch(api.user(user.id), { method: 'DELETE' })
}

export const uploadAvatar = async (body: FormData) => {
return fetch(api.avatars(), { method: 'POST', body, redirect: 'follow' }).then((r) => r.json())
}
29 changes: 9 additions & 20 deletions src/pages/admin/dashboard/cards/ProjectTable.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { defineVaDataTableColumns } from 'vuestic-ui'
import { Project } from '../../../projects/types'
import UserAvatar from '../../../users/widgets/UserAvatar.vue'
import ProjectStatusBadge from '../../../projects/components/ProjectStatusBadge.vue'
import { useProjects } from '../../../projects/composables/useProjects'
import { Pagination } from '../../../../data/pages/projects'
import { ref } from 'vue'
import { useProjectUsers } from '../../../projects/composables/useProjectUsers'
const columns = defineVaDataTableColumns([
{ label: 'Name', key: 'project_name', sortable: true },
Expand All @@ -18,11 +18,7 @@ const { projects, isLoading, sorting } = useProjects({
pagination,
})
const avatarColor = (userName: string) => {
const colors = ['primary', '#FFD43A', '#ADFF00', '#262824', 'danger']
const index = userName.charCodeAt(0) % colors.length
return colors[index]
}
const { getTeamOptions, getUserById } = useProjectUsers()
</script>

<template>
Expand All @@ -47,23 +43,16 @@ const avatarColor = (userName: string) => {
</template>
<template #cell(project_owner)="{ rowData }">
<div class="flex items-center gap-2 ellipsis max-w-[230px]">
<UserAvatar :user="rowData.project_owner" size="small" />
{{ rowData.project_owner.fullname }}
<UserAvatar
v-if="getUserById(rowData.project_owner)"
:user="getUserById(rowData.project_owner)!"
size="small"
/>
{{ getUserById(rowData.project_owner)?.fullname }}
</div>
</template>
<template #cell(team)="{ rowData: project }">
<VaAvatarGroup
size="small"
:options="
(project as Project).team.map((user) => ({
label: user.fullname,
src: user.avatar,
fallbackText: user.fullname[0],
color: avatarColor(user.fullname),
}))
"
:max="2"
/>
<VaAvatarGroup size="small" :options="getTeamOptions(project.team)" :max="2" />
</template>
<template #cell(status)="{ rowData: project }">
<ProjectStatusBadge :status="project.status" />
Expand Down
11 changes: 10 additions & 1 deletion src/pages/projects/ProjectsPage.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ref, provide } from 'vue'
import { useLocalStorage } from '@vueuse/core'
import { useProjects } from './composables/useProjects'
import ProjectCards from './widgets/ProjectCards.vue'
import ProjectTable from './widgets/ProjectsTable.vue'
import EditProjectForm from './widgets/EditProjectForm.vue'
import { Project } from './types'
import { useModal, useToast } from 'vuestic-ui'
import { useProjectUsers } from './composables/useProjectUsers'
const doShowAsCards = useLocalStorage('projects-view', true)
const { projects, update, add, isLoading, remove, pagination, sorting } = useProjects()
const { users, getTeamOptions, getUserById } = useProjectUsers()
provide('ProjectsPage', {
users,
getTeamOptions,
getUserById,
})
const projectToEdit = ref<Project | null>(null)
const doShowProjectFormModal = ref(false)
Expand Down
42 changes: 42 additions & 0 deletions src/pages/projects/composables/useProjectUsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useUsers } from '../../users/composables/useUsers'
import { Project } from '../types'

export function useProjectUsers() {
const { users } = useUsers()

const getUserById = (userId: string) => {
return users.value.find(({ id }) => userId === id)
}

const avatarColor = (userName: string) => {
const colors = ['primary', '#FFD43A', '#ADFF00', '#262824', 'danger']
const index = userName.charCodeAt(0) % colors.length
return colors[index]
}

const getTeamOptions = (team: Project['team']) => {
return team.reduce(
(acc, userId) => {
const user = getUserById(userId)

if (user) {
acc.push({
label: user.fullname,
src: user.avatar,
fallbackText: user.fullname[0],
color: avatarColor(user.fullname),
})
}

return acc
},
[] as Record<string, string>[],
)
}

return {
users,
getUserById,
getTeamOptions,
}
}
Loading

0 comments on commit 229daa6

Please sign in to comment.