diff --git a/.env b/.env
deleted file mode 100644
index 48b9d90..0000000
--- a/.env
+++ /dev/null
@@ -1 +0,0 @@
-VITE_API_URL=https://h57es3eyha.us-east-1.awsapprunner.com
\ No newline at end of file
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..a049773
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+VITE_API_URL=http://localhost:9501
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 75410cb..d979b98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ dist
dist-ssr
coverage
*.local
+.env
/cypress/videos/
/cypress/screenshots/
diff --git a/src/App.vue b/src/App.vue
index 83906be..5c88b51 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,15 +1,17 @@
-
+
-
+
-
+
{{ text }}
-
- Close
-
+ Fechar
@@ -18,19 +20,51 @@
diff --git a/src/assets/default-avatar.png b/src/assets/default-avatar.png
new file mode 100644
index 0000000..d4c720f
Binary files /dev/null and b/src/assets/default-avatar.png differ
diff --git a/src/components/HeaderMenu.vue b/src/components/HeaderMenu.vue
index c9f4f5c..45432e3 100644
--- a/src/components/HeaderMenu.vue
+++ b/src/components/HeaderMenu.vue
@@ -1,67 +1,74 @@
-
+
+
+
diff --git a/src/components/icons/DiscordIcon.vue b/src/components/icons/DiscordIcon.vue
new file mode 100644
index 0000000..bd23da3
--- /dev/null
+++ b/src/components/icons/DiscordIcon.vue
@@ -0,0 +1,8 @@
+
+
+
diff --git a/src/components/icons/Rectangle.png b/src/components/icons/Rectangle.png
new file mode 100644
index 0000000..1e12fd2
Binary files /dev/null and b/src/components/icons/Rectangle.png differ
diff --git a/src/components/icons/SearchIcon.vue b/src/components/icons/SearchIcon.vue
new file mode 100644
index 0000000..b5272f9
--- /dev/null
+++ b/src/components/icons/SearchIcon.vue
@@ -0,0 +1,34 @@
+
+
+
diff --git a/src/router/index.js b/src/router/index.js
index 55a3350..8f2688b 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -17,7 +17,6 @@ import SquadCreateView from '../views/squad/CreateView.vue'
import { useAuthStore } from '@/stores/auth';
-
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
@@ -39,89 +38,90 @@ const router = createRouter({
{
path: '/profile',
name: 'profile',
- component: ProfileView,
- meta : {
- auth: true
- }
+ component: ProfileView,
+ meta: {
+ auth: true
+ }
+ },
+ {
+ path: '/products',
+ name: 'products',
+ component: ProductsView,
+ meta: {
+ auth: false
+ }
},
- {
- path: '/products',
- name: 'products',
- component: ProductsView,
- meta : {
- auth: false
- }
- },
{
path: '/product/:uuid',
name: 'product-by-id',
component: ProductView,
- meta : {
- auth: true
- }
+ props: true,
+ meta: {
+ auth: true
+ }
},
{
- path: '/product/create',
- name: 'product-create',
- component: ProductRegistryView,
- meta : {
- auth: true,
- update: false
- }
+ path: '/product/create',
+ name: 'product-create',
+ component: ProductRegistryView,
+ meta: {
+ auth: true,
+ update: false
+ }
},
{
- path: '/product/:uuid/update',
- name: 'product-update',
- component: ProductRegistryView,
- meta : {
- auth: true,
- update: true
- }
+ path: '/product/:uuid/update',
+ name: 'product-update',
+ component: ProductRegistryView,
+ meta: {
+ auth: true,
+ update: true
+ }
},
{
path: '/squads/:uuid',
name: 'squads',
- component: SquadsView,
- meta : {
- auth: true
- }
+ component: SquadsView,
+ meta: {
+ auth: true
+ }
},
{
path: '/squad/:uuid',
name: 'squad-by-id',
component: SquadView,
- props: true,
- meta : {
- auth: true
- }
+ props: true,
+ meta: {
+ auth: true
+ }
},
{
path: '/squad/create/:productUuid',
name: 'squad-create',
component: SquadCreateView,
- meta : {
- auth: true,
- type: 'create'
- }
+ meta: {
+ auth: true,
+ type: 'create'
+ }
},
{
path: '/squad/:uuid/update',
name: 'squad-update',
component: SquadCreateView,
- meta : {
- auth: true,
- type: 'update'
- }
+ meta: {
+ auth: true,
+ type: 'update'
+ }
},
{
path: '/onboarding',
name: 'onboarding',
component: () => import('../views/OnboardingView.vue'),
- meta : {
- auth: true
- }
+ meta: {
+ auth: true
+ }
},
{
path: '/about',
@@ -132,24 +132,30 @@ const router = createRouter({
path: '/404',
name: 'not-found',
component: () => import('../views/NotFoundView.vue')
- }
+ },
]
})
router.beforeEach((to, from, next) => {
- const token = localStorage.getItem('token')
+ const token = localStorage.getItem('token')
- const auth = useAuthStore();
+ const auth = useAuthStore();
- if (to.meta.auth === true && (token === '' || token === null)) {
- router.push({ name: 'login' })
- }
+ if (to.meta.auth === true && (!token || token === '' || token === null)) {
+ router.push({ name: 'login' })
+ }
- if (auth.auth.name === '') {
- auth.loginByToken()
+ if (!auth.auth.name && token) {
+ try {
+ auth.loginByToken()
+ }
+ catch (error) {
+ console.log('Erro ao tentar logar com token', error)
+ router.push({ name: 'login' })
}
+ }
- return next()
+ return next()
});
export default router
diff --git a/src/stores/auth.js b/src/stores/auth.js
index 6d6f0d0..b95ca31 100644
--- a/src/stores/auth.js
+++ b/src/stores/auth.js
@@ -10,7 +10,7 @@ export const useAuthStore = defineStore('auth', () => {
const axiosInstance = instance;
- const auth = ref({ name: '', email: '', uuid: '', iat: '' });
+ const auth = ref({ name: '', email: '', cidade: '', estado:'', linkedin:'', discord:'', uuid: '', iat: '' });
const products = ref([]);
const squads = ref([]);
const useSnackbar = useSnackbarStore();
@@ -21,14 +21,22 @@ export const useAuthStore = defineStore('auth', () => {
const data = response.data;
if (data.error) {
- alert(data.error)
- return;
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: "error",
+ timeout: 3000,
+ });
+ return;
} else {
const token = data.token;
+ const user = data.user;
+
localStorage.setItem('token', token);
- auth.value = parseJwt(token);
+ localStorage.setItem('user', JSON.stringify(user));
+
+ auth.value = user;
await fetchProducts(auth.value.uuid);
@@ -47,17 +55,20 @@ export const useAuthStore = defineStore('auth', () => {
} catch (error) {
if (error.response?.status === 401) {
- alert(error.response.data)
+ useSnackbar.showSnackbar({
+ text: error.response?.data?.message || error.message,
+ color: "error",
+ timeout: 3000,
+ });
}
}
}
async function loginByToken() {
-
- const token = localStorage.getItem('token');
+ const user = localStorage.getItem('user');
try {
- auth.value = parseJwt(token);
+ auth.value = JSON.parse(user);
await fetchProducts(auth.value.uuid);
@@ -73,8 +84,17 @@ export const useAuthStore = defineStore('auth', () => {
} catch (error) {
if (error.response?.status === 401) {
- alert(error.response.data)
+ useSnackbar.showSnackbar({
+ text: error.response?.data?.message || error.message,
+ color: "error",
+ timeout: 3000,
+ });
}
+
+ localStorage.removeItem('token');
+ localStorage.removeItem('user');
+
+ router.push('/');
}
}
@@ -103,15 +123,16 @@ export const useAuthStore = defineStore('auth', () => {
async function logout() {
localStorage.removeItem('token');
+ localStorage.removeItem('user');
$reset();
router.push('/');
}
function $reset() {
- auth.value = { name: '', email: '', token: '' }
- products.value = []
- squads.value = []
- }
+ auth.value = { name: '', email: '', cidade: '', estado: '', linkedin: '', discord: '', uuid: '', iat: '' };
+ products.value = [];
+ squads.value = [];
+ }
function squadReset() {
squads.value = []
@@ -124,7 +145,6 @@ export const useAuthStore = defineStore('auth', () => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
- console.log('jsonPayload :', JSON.parse(jsonPayload));
return JSON.parse(jsonPayload);
}
@@ -147,13 +167,28 @@ export const useAuthStore = defineStore('auth', () => {
async function updateProfile(profile) {
try {
const response = await axiosInstance.put('/user/' + auth.value.uuid, profile);
+ const updatedUser = profile;
+
+ auth.value = { ...auth.value, ...updatedUser };
- const data = response.data;
-
- alert(data.message)
+ localStorage.setItem('user', JSON.stringify(auth.value));
+
+ useSnackbar.showSnackbar({
+ text: response.data.message,
+ color: "success",
+ timeout: 3000,
+ });
} catch (error) {
- alert(error.message)
+ useSnackbar.showSnackbar({
+ text: error.response?.data?.error || error.message,
+ color: "error",
+ timeout: 3000,
+ });
}
+ }
+
+ function getRole() {
+ return auth.value.permission.charAt(0).toUpperCase() + auth.value.permission.slice(1)
}
return {
@@ -172,7 +207,8 @@ export const useAuthStore = defineStore('auth', () => {
updateProfile,
setProducts,
squadReset,
- loginByToken
+ loginByToken,
+ getRole
}
},
diff --git a/src/stores/member.js b/src/stores/member.js
index 4dc00a7..820f577 100644
--- a/src/stores/member.js
+++ b/src/stores/member.js
@@ -1,9 +1,11 @@
import { defineStore } from 'pinia'
import memberService from '@/services/member.js'
import { ref } from 'vue'
+import { useSnackbarStore } from '@/stores/snackbar.js'
export const useMemberStore = defineStore('member', () => {
const member = ref([]);
+ const useSnackbar = useSnackbarStore();
async function fetch(uuidSquad) {
try {
@@ -11,13 +13,21 @@ export const useMemberStore = defineStore('member', () => {
const data = response;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else {
member.value = data
}
} catch (error) {
- alert('Catch: ' + error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -27,13 +37,21 @@ export const useMemberStore = defineStore('member', () => {
const data = response;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else {
fetch(data.member.squad_uuid)
}
} catch (error) {
- alert('Catch: ' + error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -43,13 +61,21 @@ export const useMemberStore = defineStore('member', () => {
const data = response;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else {
fetch(data.member.squad_uuid)
}
} catch (error) {
- alert('Catch: ' + error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -59,13 +85,21 @@ export const useMemberStore = defineStore('member', () => {
const data = response;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else {
fetch(uuidSquad)
}
} catch (error) {
- alert('Catch: ' + error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
diff --git a/src/stores/product.js b/src/stores/product.js
index 697c6c6..27ba098 100644
--- a/src/stores/product.js
+++ b/src/stores/product.js
@@ -27,11 +27,15 @@ export const useProductStore = defineStore('product', () => {
}
async function getProduct(uuid) {
- product.value = await productRequest.show(uuid)
-
+ const p = products.value.find(product => product.uuid === uuid)
+ if (p) {
+ product.value = p
+ } else {
+ product.value = await productRequest.show(uuid)
+ }
return product.value
}
-
+
async function byUser(uuid) {
products.value = await productRequest.byUser(uuid)
return products.value
@@ -42,21 +46,25 @@ export const useProductStore = defineStore('product', () => {
await tt.fetchProducts(tt.getUuid())
+ useSnackbar.showSnackbar({
+ text: 'Produto deletado com sucesso',
+ color: 'success',
+ timeout: 3000
+ });
+
router.push('/onboarding' );
//return products.value
}
async function create(product) {
const p = await productRequest.create(product)
- console.log('product created:', p);
- if (p.statusCode == 200) {
- await tt.fetchProducts(tt.getUuid())
+ if (p.statusCode == 201) {
useSnackbar.showSnackbar({
- text: 'Product created successfully',
+ text: 'Produto criado com sucesso',
color: 'success',
timeout: 3000
- })
+ });
router.push('/product/' + p.product.uuid);
}
// return products.value
@@ -76,6 +84,12 @@ export const useProductStore = defineStore('product', () => {
})
router.push('/product/' + product.uuid);
+ } else {
+ useSnackbar.showSnackbar({
+ text: p.error || 'Erro ao atualizar produto',
+ color: 'error',
+ timeout: 3000
+ });
}
// return products.value
}
diff --git a/src/stores/squad.js b/src/stores/squad.js
index f4d596d..3526252 100644
--- a/src/stores/squad.js
+++ b/src/stores/squad.js
@@ -2,28 +2,44 @@ import { defineStore } from 'pinia'
import squadService from '@/services/squad.js'
import { ref } from 'vue'
import { useAuthStore } from './auth.js'
+import { useSnackbarStore } from '@/stores/snackbar.js'
+import router from '@/router';
export const useSquadStore = defineStore('squad', () => {
const squad = ref([]);
const useAuth = useAuthStore()
+ const useSnackbar = useSnackbarStore();
+
async function fetch() {
try {
const response = await squadService.fechtBy();
const data = response.data;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else if (data.message) {
- alert(data.message)
+ useSnackbar.showSnackbar({
+ text: data.message,
+ color: 'info',
+ timeout: 3000
+ });
}
else {
squad.value = data
}
}
catch (error) {
- alert(error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -32,19 +48,32 @@ export const useSquadStore = defineStore('squad', () => {
const data = await squadService.post(squad);
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else if (data.message) {
// alert(data.message)
// await fetch()
await useAuth.fetchSquads(squad.product_uuid)
+ useSnackbar.showSnackbar({
+ text: 'Squad criado com sucesso',
+ color: 'success',
+ timeout: 3000
+ });
}
else {
squad.value = data
}
}
catch (error) {
- alert(error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -53,12 +82,21 @@ export const useSquadStore = defineStore('squad', () => {
const data = await squadService.put(squad);
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else if (data.message) {
// alert(data.message)
// await fetch()
await useAuth.fetchSquads(squad.product_uuid)
+ useSnackbar.showSnackbar({
+ text: data.message,
+ color: 'success',
+ timeout: 3000
+ });
return data
}
else {
@@ -66,7 +104,11 @@ export const useSquadStore = defineStore('squad', () => {
}
}
catch (error) {
- alert(error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
@@ -76,16 +118,30 @@ export const useSquadStore = defineStore('squad', () => {
const data = await squadService.del(uuid);
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else if (data.message) {
// alert(data.message)
// await fetch()
+ useSnackbar.showSnackbar({
+ text: 'Squad deletado com sucesso',
+ color: 'success',
+ timeout: 3000
+ });
await useAuth.squadReset()
+ router.push('/onboarding');
}
}
catch (error) {
- alert(error)
+ useSnackbar.showSnackbar({
+ text: 'Erro: ' + error,
+ color: 'error',
+ timeout: 3000
+ });
}
}
diff --git a/src/stores/user.js b/src/stores/user.js
index 4fb60f7..6bf9732 100644
--- a/src/stores/user.js
+++ b/src/stores/user.js
@@ -2,6 +2,7 @@ import { ref, computed, reactive } from 'vue'
import { defineStore } from 'pinia'
import axiosInstance from '@/services/http.js'
import router from "@/router";
+import { useSnackbarStore } from '@/stores/snackbar.js'
export const useUserStore = defineStore('user', () => {
@@ -12,21 +13,36 @@ export const useUserStore = defineStore('user', () => {
const registered = ref(false)
+ const useSnackbar = useSnackbarStore();
+
async function register(applicant) {
try {
const response = await axiosInstance.post('/user', applicant);
const data = response.data;
if (data.error) {
- alert(data.error)
+ useSnackbar.showSnackbar({
+ text: data.error,
+ color: 'error',
+ timeout: 3000
+ });
return;
} else if (data.message) {
registered.value = true;
localStorage.setItem('user', data);
+ useSnackbar.showSnackbar({
+ text: data.message,
+ color: 'success',
+ timeout: 3000
+ });
}
} catch (error) {
if (error.response.status === 401 || error.response.status === 422 || error.response.status === 404 || error.response.status === 500) {
- alert(error.response.data)
+ useSnackbar.showSnackbar({
+ text: error.response.data,
+ color: 'error',
+ timeout: 3000
+ });
}
}
}
diff --git a/src/views/user/LoginView.vue b/src/views/user/LoginView.vue
index 99a97de..abc0bda 100644
--- a/src/views/user/LoginView.vue
+++ b/src/views/user/LoginView.vue
@@ -1,7 +1,13 @@
-
+
Entrar
diff --git a/src/views/user/ProfileView.vue b/src/views/user/ProfileView.vue
index 0046d6c..e598b9f 100644
--- a/src/views/user/ProfileView.vue
+++ b/src/views/user/ProfileView.vue
@@ -13,14 +13,14 @@
{
try {
- auth.updateProfile(profile)
+ await auth.updateProfile(profile)
+
+ profile.name = auth.auth.name
+ profile.email = auth.auth.email
+ profile.cidade = auth.auth.cidade
+ profile.estado = auth.auth.estado
+ profile.linkedin = auth.auth.linkedin
+ profile.discord = auth.auth.discord
+
+ console.log('Perfil atualizado com sucesso.')
} catch (error) {
- console.log(error)
+ console.log('Erro ao atualizar o perfil:', error)
}
}
diff --git a/src/views/user/RegistryView.vue b/src/views/user/RegistryView.vue
index 8544035..e5576ec 100644
--- a/src/views/user/RegistryView.vue
+++ b/src/views/user/RegistryView.vue
@@ -146,10 +146,13 @@ const applicant = reactive({
register_token: '',
name: '',
email: '',
+ cidade: '',
+ estado: '',
password: '',
confirmPassword: '',
terms: false,
- linkedin: 'linkedin.com/in/'
+ linkedin: '',
+ discord: ''
})
const nextStep = () => {
@@ -170,6 +173,10 @@ const resetForm = () => {
applicant.register_token = ''
applicant.name = ''
applicant.email = ''
+ applicant.cidade = ''
+ applicant.estado = ''
+ applicant.linkedin = ''
+ applicant.discord = ''
applicant.password = ''
applicant.confirmPassword = ''
applicant.terms = false
@@ -178,6 +185,7 @@ const resetForm = () => {
const submitApplicant = async () => {
const newApplicant = { ...applicant }
+
if (
!newApplicant.register_token ||
!newApplicant.name ||