@goweekdays/layer-common 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/components/InvitationMain.vue +83 -53
- package/components/Layout/Header.vue +1 -1
- package/components/ListGroupSelection.vue +8 -6
- package/components/MemberForm.vue +227 -0
- package/components/MemberInvite.vue +206 -0
- package/components/MemberMain.vue +216 -262
- package/components/RoleForm.vue +1 -1
- package/components/RolePermissionMain.vue +11 -16
- package/composables/useLocalAuth.ts +3 -33
- package/composables/useMember.ts +44 -37
- package/composables/useRole.ts +6 -4
- package/composables/useVerification.ts +28 -0
- package/nuxt.config.ts +30 -0
- package/package.json +1 -1
- package/pages/forgot-password.vue +76 -0
- package/pages/login.vue +156 -0
- package/pages/logout.vue +18 -0
- package/pages/member-suspended.vue +44 -0
- package/pages/sign-up/[id].vue +214 -0
- package/pages/sign-up/index.vue +135 -0
- package/plugins/member.client.ts +13 -9
- package/types/member.d.ts +9 -0
- package/types/role.d.ts +1 -1
- package/types/verification.d.ts +9 -4
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters class="fill-height" justify="center" align-content="center">
|
|
3
|
+
<v-col cols="12" class="mb-6">
|
|
4
|
+
<v-row no-gutters justify="center">
|
|
5
|
+
<nuxt-link
|
|
6
|
+
class="text-h2 font-weight-bold text-decoration-none"
|
|
7
|
+
style="color: unset"
|
|
8
|
+
:to="{ name: 'index' }"
|
|
9
|
+
>
|
|
10
|
+
GoWeekdays
|
|
11
|
+
</nuxt-link>
|
|
12
|
+
</v-row>
|
|
13
|
+
</v-col>
|
|
14
|
+
|
|
15
|
+
<v-col
|
|
16
|
+
v-if="validating"
|
|
17
|
+
cols="12"
|
|
18
|
+
class="text-subtitle-1 font-weight-medium text-center font-italic"
|
|
19
|
+
>
|
|
20
|
+
{{ message }}
|
|
21
|
+
</v-col>
|
|
22
|
+
<v-col v-else cols="12" lg="3" md="4" sm="6">
|
|
23
|
+
<v-row no-gutters>
|
|
24
|
+
<v-col v-if="validInvitation" cols="12">
|
|
25
|
+
<v-form
|
|
26
|
+
v-model="isValid"
|
|
27
|
+
@submit.prevent="
|
|
28
|
+
submit({ firstName, lastName, password, id, referralCode, type })
|
|
29
|
+
"
|
|
30
|
+
id="form1"
|
|
31
|
+
autocomplete="off"
|
|
32
|
+
:disabled="isFormDisabled"
|
|
33
|
+
>
|
|
34
|
+
<v-row no-gutters>
|
|
35
|
+
<v-col cols="12">
|
|
36
|
+
<v-row no-gutters>
|
|
37
|
+
<InputLabel
|
|
38
|
+
class="text-capitalize"
|
|
39
|
+
title="First Name"
|
|
40
|
+
required
|
|
41
|
+
/>
|
|
42
|
+
<v-col cols="12">
|
|
43
|
+
<v-text-field
|
|
44
|
+
v-model="firstName"
|
|
45
|
+
density="comfortable"
|
|
46
|
+
:rules="[requiredRule]"
|
|
47
|
+
></v-text-field>
|
|
48
|
+
</v-col>
|
|
49
|
+
</v-row>
|
|
50
|
+
</v-col>
|
|
51
|
+
|
|
52
|
+
<v-col cols="12" class="mt-2">
|
|
53
|
+
<v-row no-gutters>
|
|
54
|
+
<InputLabel
|
|
55
|
+
class="text-capitalize"
|
|
56
|
+
title="Last Name"
|
|
57
|
+
required
|
|
58
|
+
/>
|
|
59
|
+
<v-col cols="12">
|
|
60
|
+
<v-text-field
|
|
61
|
+
v-model="lastName"
|
|
62
|
+
density="comfortable"
|
|
63
|
+
:rules="[requiredRule]"
|
|
64
|
+
></v-text-field>
|
|
65
|
+
</v-col>
|
|
66
|
+
</v-row>
|
|
67
|
+
</v-col>
|
|
68
|
+
|
|
69
|
+
<v-col cols="12">
|
|
70
|
+
<v-row no-gutters>
|
|
71
|
+
<InputLabel
|
|
72
|
+
class="text-capitalize"
|
|
73
|
+
title="Password"
|
|
74
|
+
required
|
|
75
|
+
/>
|
|
76
|
+
<v-col cols="12">
|
|
77
|
+
<InputPassword v-model="password" :rules="[requiredRule]" />
|
|
78
|
+
</v-col>
|
|
79
|
+
</v-row>
|
|
80
|
+
</v-col>
|
|
81
|
+
|
|
82
|
+
<v-col
|
|
83
|
+
v-if="message"
|
|
84
|
+
cols="12"
|
|
85
|
+
:class="'my-2 text-center font-italic' + msgColor"
|
|
86
|
+
>
|
|
87
|
+
{{ message }}
|
|
88
|
+
</v-col>
|
|
89
|
+
|
|
90
|
+
<v-col cols="12" v-if="!isFormDisabled">
|
|
91
|
+
<v-btn
|
|
92
|
+
block
|
|
93
|
+
type="submit"
|
|
94
|
+
variant="text"
|
|
95
|
+
:disabled="!isValid"
|
|
96
|
+
rounded="xl"
|
|
97
|
+
size="large"
|
|
98
|
+
:loading="loading"
|
|
99
|
+
>
|
|
100
|
+
submit
|
|
101
|
+
</v-btn>
|
|
102
|
+
</v-col>
|
|
103
|
+
</v-row>
|
|
104
|
+
</v-form>
|
|
105
|
+
</v-col>
|
|
106
|
+
|
|
107
|
+
<v-col
|
|
108
|
+
v-else
|
|
109
|
+
cols="12"
|
|
110
|
+
class="text-subtitle-1 font-weight-medium text-center font-italic"
|
|
111
|
+
>
|
|
112
|
+
<span>{{ message }}</span>
|
|
113
|
+
<v-row no-gutters justify="center">
|
|
114
|
+
<nuxt-link :to="{ name: 'index' }">Go to homepage</nuxt-link>
|
|
115
|
+
</v-row>
|
|
116
|
+
</v-col>
|
|
117
|
+
</v-row>
|
|
118
|
+
</v-col>
|
|
119
|
+
</v-row>
|
|
120
|
+
</template>
|
|
121
|
+
|
|
122
|
+
<script setup lang="ts">
|
|
123
|
+
definePageMeta({
|
|
124
|
+
layout: "plain",
|
|
125
|
+
});
|
|
126
|
+
const { verify } = useLocalAuth();
|
|
127
|
+
|
|
128
|
+
const id = (useRoute().params.id as string) ?? "";
|
|
129
|
+
|
|
130
|
+
const validating = ref(true);
|
|
131
|
+
const validInvitation = ref(false);
|
|
132
|
+
|
|
133
|
+
const message = ref("Validating invitation...");
|
|
134
|
+
const msgColor = ref("text-error");
|
|
135
|
+
|
|
136
|
+
const type = ref("");
|
|
137
|
+
const referralCode = ref("");
|
|
138
|
+
const loading = ref(false);
|
|
139
|
+
|
|
140
|
+
async function validate() {
|
|
141
|
+
try {
|
|
142
|
+
const result = await verify(id);
|
|
143
|
+
|
|
144
|
+
if (result.type) {
|
|
145
|
+
type.value = result.type;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (result.referralCode) {
|
|
149
|
+
referralCode.value = result.referralCode;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
validInvitation.value = true;
|
|
153
|
+
message.value = "";
|
|
154
|
+
} catch (error: any) {
|
|
155
|
+
message.value = error.data.message;
|
|
156
|
+
}
|
|
157
|
+
validating.value = false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await validate();
|
|
161
|
+
|
|
162
|
+
const { requiredRule } = useUtils();
|
|
163
|
+
const firstName = ref("");
|
|
164
|
+
const lastName = ref("");
|
|
165
|
+
const password = ref("");
|
|
166
|
+
|
|
167
|
+
const isValid = ref(false);
|
|
168
|
+
|
|
169
|
+
const { createUserByVerification } = useUser();
|
|
170
|
+
|
|
171
|
+
const countdown = ref(5); // Countdown from 5 seconds
|
|
172
|
+
const isFormDisabled = ref(false);
|
|
173
|
+
|
|
174
|
+
async function submit({
|
|
175
|
+
firstName = "",
|
|
176
|
+
lastName = "",
|
|
177
|
+
password = "",
|
|
178
|
+
id = "",
|
|
179
|
+
type = "",
|
|
180
|
+
referralCode = "",
|
|
181
|
+
} = {}) {
|
|
182
|
+
message.value = "";
|
|
183
|
+
loading.value = true;
|
|
184
|
+
try {
|
|
185
|
+
const res = await createUserByVerification({
|
|
186
|
+
firstName,
|
|
187
|
+
lastName,
|
|
188
|
+
password,
|
|
189
|
+
id,
|
|
190
|
+
type,
|
|
191
|
+
referralCode,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
isFormDisabled.value = true;
|
|
195
|
+
|
|
196
|
+
msgColor.value = " text-none";
|
|
197
|
+
|
|
198
|
+
message.value = `${res.message} Redirecting in ${countdown.value} seconds...`;
|
|
199
|
+
|
|
200
|
+
// Start countdown
|
|
201
|
+
const interval = setInterval(() => {
|
|
202
|
+
countdown.value--;
|
|
203
|
+
message.value = `${res.message} Redirecting in ${countdown.value} seconds...`;
|
|
204
|
+
if (countdown.value <= 0) {
|
|
205
|
+
clearInterval(interval);
|
|
206
|
+
navigateTo({ name: "index" });
|
|
207
|
+
}
|
|
208
|
+
}, 1000);
|
|
209
|
+
} catch (error: any) {
|
|
210
|
+
message.value = error.data.message;
|
|
211
|
+
}
|
|
212
|
+
loading.value = false;
|
|
213
|
+
}
|
|
214
|
+
</script>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters class="fill-height" justify="center" align-content="center">
|
|
3
|
+
<v-col cols="12" lg="3" md="4" sm="6">
|
|
4
|
+
<v-form
|
|
5
|
+
v-model="valid"
|
|
6
|
+
@submit.prevent="submit(email)"
|
|
7
|
+
:disabled="loading"
|
|
8
|
+
>
|
|
9
|
+
<v-row no-gutters>
|
|
10
|
+
<v-col cols="12">
|
|
11
|
+
<v-row no-gutters justify="center">
|
|
12
|
+
<nuxt-link
|
|
13
|
+
class="text-h2 font-weight-bold text-decoration-none"
|
|
14
|
+
style="color: unset"
|
|
15
|
+
:to="{ name: 'index' }"
|
|
16
|
+
>
|
|
17
|
+
GoWeekdays
|
|
18
|
+
</nuxt-link>
|
|
19
|
+
</v-row>
|
|
20
|
+
</v-col>
|
|
21
|
+
|
|
22
|
+
<v-col cols="12" class="mt-6">
|
|
23
|
+
<v-row no-gutters>
|
|
24
|
+
<v-col cols="12" class="text-h6 font-weight-bold"> Email </v-col>
|
|
25
|
+
<v-col cols="12">
|
|
26
|
+
<v-text-field
|
|
27
|
+
v-model="email"
|
|
28
|
+
:rules="[requiredRule, emailRule]"
|
|
29
|
+
></v-text-field>
|
|
30
|
+
</v-col>
|
|
31
|
+
</v-row>
|
|
32
|
+
</v-col>
|
|
33
|
+
|
|
34
|
+
<!-- Honeypot Field (Hidden) -->
|
|
35
|
+
<v-text-field
|
|
36
|
+
v-model="goWeekdaysHoneypot"
|
|
37
|
+
label="Leave this field empty"
|
|
38
|
+
class="goWeekdaysHoneypot"
|
|
39
|
+
autocomplete="off"
|
|
40
|
+
></v-text-field>
|
|
41
|
+
|
|
42
|
+
<v-col cols="12">
|
|
43
|
+
<v-row no-gutters justify="center">
|
|
44
|
+
<v-col
|
|
45
|
+
cols="12"
|
|
46
|
+
class="text-subtitle-1 font-weight-medium text-center font-italic"
|
|
47
|
+
>
|
|
48
|
+
{{ message }}
|
|
49
|
+
</v-col>
|
|
50
|
+
</v-row>
|
|
51
|
+
</v-col>
|
|
52
|
+
|
|
53
|
+
<v-col cols="12" class="mt-4">
|
|
54
|
+
<v-btn
|
|
55
|
+
block
|
|
56
|
+
type="submit"
|
|
57
|
+
variant="tonal"
|
|
58
|
+
:disabled="!valid"
|
|
59
|
+
rounded="xl"
|
|
60
|
+
size="large"
|
|
61
|
+
class="text-none"
|
|
62
|
+
:loading="loading"
|
|
63
|
+
>
|
|
64
|
+
Sign up
|
|
65
|
+
</v-btn>
|
|
66
|
+
</v-col>
|
|
67
|
+
|
|
68
|
+
<v-col cols="12" class="my-4">
|
|
69
|
+
<v-divider></v-divider>
|
|
70
|
+
</v-col>
|
|
71
|
+
|
|
72
|
+
<v-col cols="12" class="text-center font-weight-bold">
|
|
73
|
+
<v-btn
|
|
74
|
+
block
|
|
75
|
+
variant="flat"
|
|
76
|
+
color="black"
|
|
77
|
+
rounded="xl"
|
|
78
|
+
size="large"
|
|
79
|
+
class="text-none"
|
|
80
|
+
:to="{ name: 'login' }"
|
|
81
|
+
>
|
|
82
|
+
Login
|
|
83
|
+
</v-btn>
|
|
84
|
+
</v-col>
|
|
85
|
+
</v-row>
|
|
86
|
+
</v-form>
|
|
87
|
+
</v-col>
|
|
88
|
+
</v-row>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
definePageMeta({
|
|
93
|
+
layout: "plain",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const { requiredRule, emailRule } = useUtils();
|
|
97
|
+
const email = ref("");
|
|
98
|
+
const valid = ref(false);
|
|
99
|
+
|
|
100
|
+
const goWeekdaysHoneypot = ref("");
|
|
101
|
+
|
|
102
|
+
const { signUp } = useVerification();
|
|
103
|
+
|
|
104
|
+
const message = ref("");
|
|
105
|
+
|
|
106
|
+
const loading = ref(false);
|
|
107
|
+
|
|
108
|
+
async function submit(email = "") {
|
|
109
|
+
loading.value = true;
|
|
110
|
+
if (goWeekdaysHoneypot.value) {
|
|
111
|
+
console.warn("Bot detected! Form rejected.");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await signUp(email);
|
|
117
|
+
message.value = "Verification email sent! Please check your inbox.";
|
|
118
|
+
} catch (error: any) {
|
|
119
|
+
message.value = error.response._data.message;
|
|
120
|
+
} finally {
|
|
121
|
+
loading.value = false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style scoped>
|
|
127
|
+
.goWeekdaysHoneypot {
|
|
128
|
+
position: absolute;
|
|
129
|
+
left: -9999px;
|
|
130
|
+
opacity: 0;
|
|
131
|
+
height: 0;
|
|
132
|
+
width: 0;
|
|
133
|
+
pointer-events: none;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
package/plugins/member.client.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default defineNuxtPlugin(() => {
|
|
2
2
|
const router = useRouter();
|
|
3
|
-
const {
|
|
3
|
+
const { getByApp } = useMember();
|
|
4
4
|
const { getById: getRoleById } = useRole();
|
|
5
5
|
const { membership, permissions } = useLocalAuth();
|
|
6
6
|
|
|
@@ -13,18 +13,22 @@ export default defineNuxtPlugin(() => {
|
|
|
13
13
|
|
|
14
14
|
const userId = useCookie("user").value ?? "";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
membership.value = member;
|
|
16
|
+
try {
|
|
17
|
+
const member = await getByApp({ app: APP, user: userId, org });
|
|
18
|
+
membership.value = member;
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const role = await getRoleById(member.role);
|
|
21
|
+
permissions.value = role.permissions ?? [];
|
|
22
|
+
|
|
23
|
+
if (member.status === "suspended") {
|
|
24
24
|
navigateTo({
|
|
25
|
-
name: "
|
|
25
|
+
name: "member-suspended",
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
navigateTo({
|
|
30
|
+
name: "index",
|
|
31
|
+
});
|
|
28
32
|
}
|
|
29
33
|
});
|
|
30
34
|
});
|
package/types/member.d.ts
CHANGED
|
@@ -5,8 +5,17 @@ declare type TMember = {
|
|
|
5
5
|
name: string;
|
|
6
6
|
user: string;
|
|
7
7
|
role: string;
|
|
8
|
+
roleName?: string;
|
|
8
9
|
status?: string;
|
|
9
10
|
createdAt?: string;
|
|
10
11
|
updatedAt?: string;
|
|
11
12
|
deletedAt?: string;
|
|
12
13
|
};
|
|
14
|
+
|
|
15
|
+
declare type TMemberInvitation = {
|
|
16
|
+
_id?: string;
|
|
17
|
+
email: string;
|
|
18
|
+
app: string;
|
|
19
|
+
org: string;
|
|
20
|
+
role: string;
|
|
21
|
+
};
|
package/types/role.d.ts
CHANGED
package/types/verification.d.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
declare type
|
|
1
|
+
declare type TVerMetadata = {
|
|
2
|
+
name?: string;
|
|
2
3
|
app?: string;
|
|
3
4
|
role?: string;
|
|
5
|
+
roleName?: string;
|
|
6
|
+
referralCode?: string;
|
|
7
|
+
org?: string;
|
|
8
|
+
orgName?: string;
|
|
4
9
|
};
|
|
5
10
|
|
|
6
|
-
declare type
|
|
11
|
+
declare type TVer = {
|
|
7
12
|
_id?: string;
|
|
8
13
|
type: string;
|
|
9
14
|
email: string;
|
|
10
|
-
metadata?:
|
|
15
|
+
metadata?: TVerMetadata;
|
|
11
16
|
status?: string;
|
|
12
17
|
createdAt: string;
|
|
13
|
-
updatedAt?: string
|
|
18
|
+
updatedAt?: string;
|
|
14
19
|
expireAt: string;
|
|
15
20
|
};
|