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

Add members #40

Open
wants to merge 12 commits into
base: development_2.0.0
Choose a base branch
from
6 changes: 3 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
"@mdi/font": "7.4.47",
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
"vuetify": "^3.6.11"
"vue": "^3.4.31"
},
"devDependencies": {
"@babel/types": "^7.24.7",
Expand All @@ -38,6 +37,7 @@
"vite-plugin-vue-layouts": "^0.11.0",
"vite-plugin-vuetify": "^2.0.3",
"vue-router": "^4.4.0",
"vue-tsc": "^2.0.26"
"vue-tsc": "^2.0.26",
"vuetify": "^3.6.13"
}
}
6 changes: 3 additions & 3 deletions client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 12 additions & 6 deletions client/src/api/axios.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import axios, { AxiosInstance } from 'axios';
import axios, { AxiosInstance } from 'axios'

const AuthClient: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_ENDPOINT,
baseURL: import.meta.env.VITE_APP_ENDPOINT,
timeout: 1000,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Load it from the window instead

headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("token"),
Authorization: 'Bearer ' + localStorage.getItem('token'),
},
});
})

const BaseClient: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_ENDPOINT,
timeout: 1000,
});
})

export { AuthClient, BaseClient };
async function Search (searchInput:any) {
return await AuthClient.get(`/members/search/${searchInput}`)
}
async function getProjectMembers (projectId:any) {
return await AuthClient.get(`/members/project/${projectId}/members/`)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

use members without projects, should be /api/members/all/
use this endpoint /members/project/${projectId}/members/ only inside an active project

export default { AuthClient, BaseClient, Search }
2 changes: 0 additions & 2 deletions client/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AppFooter: typeof import('./components/AppFooter.vue')['default']
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Test: typeof import('./components/test.vue')['default']
Expand Down
4 changes: 3 additions & 1 deletion client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import App from './App.vue'

// Composables
import { createApp } from 'vue'
import router from './router'
import vuetify from './plugins/vuetify'

const app = createApp(App)

registerPlugins(app)

app.mount('#app')
app.use(router).use(vuetify).mount('#app')
191 changes: 191 additions & 0 deletions client/src/pages/AddMembers.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<template>
<div style="margin-left: 7cm; margin-right: 7cm;">
<v-container>
<v-row>
Comment on lines +2 to +4
Copy link
Collaborator

Choose a reason for hiding this comment

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

You need to load the navbar here

<p class="mt-2 text-h4 text-blue-darken-4" variant="h5">ALL MEMBERS</p>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<p class="mt-2 text-h4 text-blue-darken-4" variant="h5">ALL MEMBERS</p>
<p class="mt-2 text-h4 text-blue-darken-4" variant="h5">All members</p>

<v-spacer />
<v-btn
color="primary"
@click="addMemberDialog=true"
>
INVITE MEMBERS
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
INVITE MEMBERS
Invite member

</v-btn>
</v-row>

<v-dialog v-model="addMemberDialog" max-width="600px">
<v-card>
<v-form>
<v-card-title>
<br>
<v-divider />
</v-card-title>
<v-card-text>
<v-text-field
v-model="inviteNewMember.first_name"
density="compact"
placeholder="First Name"
prepend-inner-icon="mdi-account-outline"
variant="outlined"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add the validation rules, and apply it to all inputs

/>
<v-text-field
v-model="inviteNewMember.last_name"
density="compact"
placeholder="Last Name"
prepend-inner-icon="mdi-account-outline"
variant="outlined"
/>
<v-text-field
v-model="inviteNewMember.email"
density="compact"
placeholder="Email"
prepend-inner-icon="mdi-email-outline"
variant="outlined"
/>
<p>Permission</p>
<v-select
:items="['Full access', 'Admin access']"
label="Select"
/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<p>Permission</p>
<v-select
:items="['Full access', 'Admin access']"
label="Select"
/>
<v-select
:items="['Full access', 'Admin access']"
label="Permission"
/>

also, use an enum to normalizre the value, the backend require an exact pattern see the enum there

class PERMISSION_CHOICES(models.TextChoices):
    FULL_ACCESS = "full_access", "Full access"
    ADMIN_ACCESS = "admin_access", "Admin access"

so you need to send the full_access or admin_access as the value

Suggested change
<p>Permission</p>
<v-select
:items="['Full access', 'Admin access']"
label="Select"
/>
<v-select
:items="[{name: "Full access" value: 'full_access'}, {name: 'Admin access', value: 'admin_access'}]"
label="Permission"
/>

<v-divider />
<v-card-actions>
<v-spacer />
<v-btn color="info" @click="addMemberDialog = false">Close</v-btn>
<v-btn color="success" :disabled="loadingAdd" :loading="loadingAdd" @click="addMember">ADD+</v-btn>
</v-card-actions>
</v-card-text>
</v-form>
</v-card>
</v-dialog>

<v-row>
<p class="mt-2 text-h6 text-grey-darken-2 mb-8" variant="h6">There are {{ count }} members registered</p>
</v-row>
<br>

<v-row>
<h4 class="mb-2">Search Members</h4>
</v-row>

<v-row>
<v-text-field v-model="searchText" label="Search" variant="outlined" />
<v-btn color="primary" style="height: 56px; width:80px; padding: 0; margin: 0;" variant="outlined" @click="SearchMember">Search</v-btn>
</v-row>

<v-row>
<v-col
v-for="member in members"
:key="member.email"
cols="12"
md="4"
sm="6"
>
<v-card class="ma-2" outlined>
<!-- implement viewMember -->
<v-card-subtitle>{{ member.full_name }}</v-card-subtitle>
<v-card-actions>
<v-btn @click="viewMember(member.id)">View Details</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</div>
</template>

<script>
import { defineProps, ref } from 'vue'
import axios from '@/api/axios'

export default {
setup () {
const props = defineProps({
count: {
type: Number,
required: true,
},
members: {
type: Array,
required: true,
},
project_id: {
type: string,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use String instead

required: true,
},
})

const inviteNewMember = ref({
first_name: '',
last_name: '',
email: '',
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Better to define an interface for the data


const addMemberDialog = ref(false)

const searchText = ref('')

const loadingAdd = ref(false)

const addMember = () => {
loadingAdd.value = true
try {
notifier.notify({
title: 'success',
description: 'member added successfully',
showProgressBar: true,
timeout: 7_000,
type: 'success',
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

The message will be returned from the backend

} catch (error) {
console.error(error)
notifier.notify({
title: 'Fail',
description: 'cannot add member',
showProgressBar: true,
timeout: 7_000,
type: 'error',
})
} finally {
loadingAdd.value = false
}
}

const SearchMember = async () => {
try {
members.value = await axios.Search(searchText.value)
} catch (error) {
console.error(error)
notifier.notify({
title: 'Fail',
description: 'no member found',
showProgressBar: true,
timeout: 7_000,
type: 'error',
})
}
}

async function getMembers () {
try {
members = await axios.getProjectMembers(project_id)
} catch (error) {
console.error(error)
}
}

onMounted(() => {
getMembers()
})

return {
props,
SearchMember,
searchText,
inviteNewMember,
addMemberDialog,
addMember,
loadingAdd,
}
},

}
</script>
2 changes: 1 addition & 1 deletion client/src/plugins/vuetify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ import { createVuetify } from 'vuetify'
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({
theme: {
defaultTheme: 'dark',
defaultTheme: 'light',
},
})
3 changes: 2 additions & 1 deletion client/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
// Composables
import { createRouter, createWebHistory } from 'vue-router/auto'


const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/', component: () => import('@/pages/DashboardView.vue') }
{ path: '/', component: () => import('@/pages/AddMembers.vue') }
],
})

Expand Down
1 change: 1 addition & 0 deletions client/src/typed-router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ declare module 'vue-router/auto-routes' {
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/AddMembers': RouteRecordInfo<'/AddMembers', '/AddMembers', Record<never, never>, Record<never, never>>,
'/DashboardView': RouteRecordInfo<'/DashboardView', '/DashboardView', Record<never, never>, Record<never, never>>,
}
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"vuetify": "3.7.0-beta.1"
}
}
Loading
Loading