Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix#968/users page #970

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/sidebar/NavigationRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ export default {
name: 'pricing-plans',
displayName: 'menu.pricing-plans',
},
{
name: 'users',
displayName: 'menu.users',
},
{
name: 'billing',
displayName: 'menu.billing',
Expand Down
2 changes: 1 addition & 1 deletion src/components/va-charts/VaChart.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<!-- @vue-ignore -->
<component :is="chartComponent" ref="chart" :chart-data="data" :chart-options="chartOptions" class="va-chart" />
<Component :is="chartComponent" ref="chart" :chart-data="data" :chart-options="chartOptions" class="va-chart" />
</template>

<script lang="ts" setup>
Expand Down
190 changes: 190 additions & 0 deletions src/data/pages/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import { sleep } from '../../services/utils'
m0ksem marked this conversation as resolved.
Show resolved Hide resolved
import { repeatArray } from '../../services/utils'
m0ksem marked this conversation as resolved.
Show resolved Hide resolved
import { User } from './../../pages/users/types'

export const users = repeatArray<User>(50, [
m0ksem marked this conversation as resolved.
Show resolved Hide resolved
{
m0ksem marked this conversation as resolved.
Show resolved Hide resolved
id: 1,
fullname: 'Patrik Radkow',
email: '[email protected]',
username: 'magicpan',
role: 'user',
projects: 3,
avatar: '',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 2,
fullname: 'Martin Hoff',
email: '[email protected]',
username: 'admin',
role: 'admin',
projects: 5,
avatar: '😍',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 3,
fullname: 'Liz Macintosh',
email: '[email protected]',
username: 'ebrown',
role: 'user',
projects: 2,
avatar: 'https://randomuser.me/api/portraits/men/1.jpg',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 4,
fullname: 'M2',
email: '[email protected]',
username: 'mrm',
role: 'owner',
projects: 1,
avatar: '',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 5,
fullname: 'Kevin Smith',
email: '[email protected]',
username: 'kevin13',
role: 'user',
projects: 13,
avatar: 'https://randomuser.me/api/portraits/men/2.jpg',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 6,
fullname: 'Martin Hoff',
email: '[email protected]',
username: 'martin3',
role: 'user',
projects: 2,
avatar: 'https://randomuser.me/api/portraits/men/3.jpg',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 7,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add some more variety, maybe 10 users on repeat?

image

Also maybe only nice images, letters are placeholders and we don't have to cover all cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there. Images are great, but when you open the page you see this:

image

It would be great to see this instead:

image

Can we maybe remove John Doe, Martin Hoff etc users without images?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Users without images were used in design, and I'd keep them as an example.

fullname: 'John Doe',
email: '[email protected]',
username: 'john',
role: 'user',
projects: 1,
avatar: '',
active: true,
notes: '',
},
{
id: 8,
fullname: 'Maksim Nedo',
email: '[email protected]',
username: 'maksim',
role: 'admin',
projects: 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Let's use project names.
I'm fine without objects, but the way it is right now - I can't say the page is finished. So let's make it look good in this PR, then perhaps move to objects in #984 pr.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean something like the list below, number is not meaningful

"NexaFlow Manager"
"OrbitTrack Suite"
"DataPulse Portal"
"InnoSight Platform"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have user role specific for project in data, but I can display projects which user a part of.
image

avatar: 'https://avatars.githubusercontent.com/u/23530004?v=4',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 9,
fullname: 'Dmitry Kuzmenko',
email: '[email protected]',
username: 'dd',
role: 'user',
projects: 1,
avatar: '',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 10,
fullname: 'Rayan Gosling',
email: '[email protected]',
username: 'rayan',
role: 'user',
projects: 1,
avatar: '',
active: true,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 11,
fullname: 'Laura Smith',
email: '[email protected]',
username: 'bbb',
role: 'user',
projects: 3,
avatar: '',
active: false,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
{
id: 12,
fullname: 'Ted Mosby',
email: '[email protected]',
username: 'gamer777',
role: 'user',
projects: 5,
avatar: '😭',
active: false,
notes: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, voluptatum.',
},
]).map((u, index) => ({ ...u, id: index }))

// Simulate API calls
export type Filters = {
isActive: boolean
m0ksem marked this conversation as resolved.
Show resolved Hide resolved
search: string
pagination: {
page: number
perPage: number
total: number
}
}

export const getUsers = async (filters: Partial<Filters>) => {
await sleep(1000)
const { isActive, search } = filters
let filteredUsers = users

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

if (search) {
filteredUsers = users.filter((user) => user.fullname.toLowerCase().includes(search.toLowerCase()))
}

const { page = 1, perPage = 10 } = filters.pagination || {}
return {
data: filteredUsers.slice((page - 1) * perPage, page * perPage),
pagination: {
page,
perPage,
total: filteredUsers.length,
},
}
}

export const addUser = async (user: User) => {
await sleep(1000)
users.unshift(user)
}

export const updateUser = async (user: User) => {
await sleep(1000)
const index = users.findIndex((u) => u.id === user.id)
users[index] = user
}

export const removeUser = async (user: User) => {
await sleep(1000)
users.splice(
users.findIndex((u) => u.id === user.id),
1,
)
}
3 changes: 2 additions & 1 deletion src/i18n/locales/gb.json
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@
"line-maps": "Line Maps",
"login-singup": "Login/Signup",
"404-pages": "404 Pages",
"faq": "Faq"
"faq": "Faq",
"users": "Users"
},
"messages": {
"all": "See all messages",
Expand Down
2 changes: 1 addition & 1 deletion src/pages/admin/dashboard/DashboardTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</template>
</VaTabs>
<VaSeparator />
<component :is="tabs[activeTabName]" @submit="submit" />
<Component :is="tabs[activeTabName]" @submit="submit" />
</VaCardContent>
</VaCard>
</template>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/admin/ui/spinners/Spinners.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<div v-for="(group, i) in groups" :key="i" class="grid grid-cols-12 gap-6">
<div v-for="item in group" :key="item" class="sm:col-span-6 col-span-12 lg:col-span-3 flex flex-col">
<div class="h-[140px] flex justify-center items-center">
<component
<Component
:is="getComponent(item)"
:animation-duration="config.duration"
:color="computedSpinnersColor"
Expand Down
3 changes: 1 addition & 2 deletions src/pages/payments/payment-system/PaymentSystem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
</div>
</template>

<script lang="ts" setup>
import { defineProps } from 'vue'
<script setup lang="ts">
import { PaymentSystemType } from '../types'

const props = defineProps<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</template>

<script lang="ts" setup>
import { defineProps, computed, defineEmits } from 'vue'
import { computed } from 'vue'
import PaymentSystem from '../../payment-system/PaymentSystem.vue'
import { PaymentCard } from '../../types'

Expand Down
102 changes: 102 additions & 0 deletions src/pages/users/UsersPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<script setup lang="ts">
import { ref } from 'vue'
import UsersTable from './widgets/UsersTable.vue'
import EditUserForm from './widgets/EditUserForm.vue'
import { User } from './types'
import { useUsers } from './composables/useUsers'
import { Filters } from '../../data/pages/users'
import { useToast } from 'vuestic-ui'

const filters = ref<Filters>({
isActive: true,
search: '',
pagination: {
page: 1,
perPage: 10,
total: 250,
},
})

const doShowEditUserModal = ref(false)

const { users, isLoading, ...usersApi } = useUsers(filters)

const userToEdit = ref<User | null>(null)

const showEditUserModal = (user: User) => {
userToEdit.value = user
doShowEditUserModal.value = true
}

const showAddUserModal = () => {
userToEdit.value = null
doShowEditUserModal.value = true
}

const { init: notify } = useToast()

const onUserSaved = async (user: User) => {
if (userToEdit.value) {
await usersApi.update(user)
notify({
message: `${user.fullname} has been updated`,
color: 'success',
})
} else {
usersApi.add(user)
notify({
message: `${user.fullname} has been updated`,
color: 'success',
})
}
}

const onUserDelete = async (user: User) => {
await usersApi.remove(user)
notify({
message: `${user.fullname} has been deleted`,
color: 'success',
})
}
</script>

<template>
<h1 class="page-title">Users</h1>

<VaCard>
<VaCardContent>
<div class="flex flex-col md:flex-row gap-2 mb-2">
<div class="flex flex-col md:flex-row gap-2 justify-start">
<VaButtonToggle
v-model="filters.isActive"
color="background-element"
border-color="background-element"
:options="[
{ label: 'Active', value: true },
{ label: 'Inactive', value: false },
]"
/>
<VaInput v-model="filters.search" placeholder="Search">
<template #prependInner>
<VaIcon name="search" color="secondary" size="small" />
</template>
</VaInput>
</div>
<VaSpacer />
<VaButton @click="showAddUserModal">Add User</VaButton>
</div>

<UsersTable
:users="users"
:loading="isLoading"
:pagination="filters.pagination"
@editUser="showEditUserModal"
@deleteUser="onUserDelete"
/>
</VaCardContent>
</VaCard>

<VaModal v-slot="{ hide }" v-model="doShowEditUserModal" hide-default-actions>
<EditUserForm :user="userToEdit" @close="hide" @save="onUserSaved" />
</VaModal>
</template>
Loading