WIP
This commit is contained in:
@@ -8,9 +8,6 @@ import HelpAndContact from '@/views/documentation/HelpAndContact.vue'
|
|||||||
import TermsAndConditions from '@/views/documentation/TermsAndConditions.vue'
|
import TermsAndConditions from '@/views/documentation/TermsAndConditions.vue'
|
||||||
import LoginView from '../views/LoginView.vue'
|
import LoginView from '../views/LoginView.vue'
|
||||||
import PaymentCompleted from '../views/PayementCompleted.vue'
|
import PaymentCompleted from '../views/PayementCompleted.vue'
|
||||||
import SignupView from '../views/SignupView.vue'
|
|
||||||
import Join from '../views/main/Join.vue'
|
|
||||||
import Register from '../views/main/Register.vue'
|
|
||||||
import Home from '../views/main/Home.vue'
|
import Home from '../views/main/Home.vue'
|
||||||
import Wallet from '../views/main/Wallet.vue'
|
import Wallet from '../views/main/Wallet.vue'
|
||||||
import ProfilePage from '@/views/profile/ProfilePage.vue'
|
import ProfilePage from '@/views/profile/ProfilePage.vue'
|
||||||
@@ -118,22 +115,6 @@ const routes = [
|
|||||||
path: '/content/post',
|
path: '/content/post',
|
||||||
component: PostContent,
|
component: PostContent,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
path: '/join',
|
|
||||||
name: 'join',
|
|
||||||
component: Join
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/register',
|
|
||||||
name: 'register',
|
|
||||||
component: Register
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/signup',
|
|
||||||
name: 'signup',
|
|
||||||
component: SignupView
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: 'login',
|
name: 'login',
|
||||||
|
|||||||
@@ -2,18 +2,15 @@
|
|||||||
import {useSessionStorage} from "@vueuse/core";
|
import {useSessionStorage} from "@vueuse/core";
|
||||||
import {useClient} from "@/plugins/api.js";
|
import {useClient} from "@/plugins/api.js";
|
||||||
import {useAuthStore} from "@/stores/authStore.js";
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
import {watch} from "vue";
|
import {watch, onMounted} from "vue";
|
||||||
|
|
||||||
export const useSubscriptionStore = defineStore(
|
export const useSubscriptionStore = defineStore(
|
||||||
'subscription',
|
'subscription',
|
||||||
() => {
|
() => {
|
||||||
|
|
||||||
const subscriptions = useSessionStorage(
|
|
||||||
'subscription-subscriptions',
|
|
||||||
{})
|
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const authWatcher = watch(
|
|
||||||
|
watch(
|
||||||
() => authStore.isAuthenticated,
|
() => authStore.isAuthenticated,
|
||||||
async (newValue) => {
|
async (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
@@ -23,38 +20,18 @@ export const useSubscriptionStore = defineStore(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const subscriptions = useSessionStorage(
|
||||||
|
'subscription-subscriptions',
|
||||||
|
{})
|
||||||
|
|
||||||
function isSubscribeTo(creatorId) {
|
function isSubscribeTo(creatorId) {
|
||||||
return !!subscriptions.value[creatorId];
|
return !!subscriptions.value[creatorId];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function subscribeTo(creatorId) {
|
|
||||||
try {
|
|
||||||
const client = useClient()
|
|
||||||
const response = await client.post(
|
|
||||||
`/api/creators/${creatorId}/subscribe`
|
|
||||||
);
|
|
||||||
subscriptions.value[creatorId] = response.data;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error subscribing to creator", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function unsubscribeFrom(creatorId) {
|
|
||||||
try {
|
|
||||||
const client = useClient()
|
|
||||||
const response = await client.post(
|
|
||||||
`/api/creators/${creatorId}/unsubscribe`
|
|
||||||
);
|
|
||||||
delete subscriptions.value[creatorId];
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error unsubscribing from creator", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadSubscriptions() {
|
async function loadSubscriptions() {
|
||||||
try {
|
try {
|
||||||
const client = useClient()
|
const client = useClient()
|
||||||
const response = await client.get(`/api/subscriptions`);
|
const response = await client.get(`/api/membership/active`);
|
||||||
|
|
||||||
subscriptions.value = response.data.reduce(
|
subscriptions.value = response.data.reduce(
|
||||||
(acc, sub) => {
|
(acc, sub) => {
|
||||||
@@ -67,5 +44,5 @@ export const useSubscriptionStore = defineStore(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {subscriptions, isSubscribeTo, subscribeTo, unsubscribeFrom}
|
return {subscriptions, isSubscribeTo}
|
||||||
});
|
});
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<template>
|
|
||||||
<v-app style="background-color: #f4f4f4;">
|
|
||||||
<v-row>
|
|
||||||
<v-col cols=6 align="center">
|
|
||||||
<v-img class="login-picture" max-width="500" src="/images/hutopymedia/loginpage/loginhutopy.png"
|
|
||||||
style="margin-top: 100px; margin-bottom: 50px"></v-img>
|
|
||||||
<div class="p-12 bg-white border border-gray-200 rounded-lg mt-6">
|
|
||||||
<h1 class="mb-6 text-2xl font-bold">Sign up</h1>
|
|
||||||
<p class="mb-6 texte-gray-500">
|
|
||||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
|
||||||
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an
|
|
||||||
unknown printer
|
|
||||||
took a galley of type and scrambled it to make a type specimen book. It has survived not
|
|
||||||
only
|
|
||||||
five centuries, but also the leap into electronic typesetting, remaining essentially
|
|
||||||
unchanged. It
|
|
||||||
was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum
|
|
||||||
passages,
|
|
||||||
and more recently with desktop publishing software like Aldus PageMaker including versions
|
|
||||||
of Lorem
|
|
||||||
Ipsum.
|
|
||||||
</p>
|
|
||||||
<p class="font-bold">
|
|
||||||
Already have an account?
|
|
||||||
<RouterLink :to="{ 'name': 'login' }" class="underline">Click here</RouterLink> to log in!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6" sm="6" md="6" lg="6">
|
|
||||||
<div class="p-12 bg-white border border-gray-200 rounded-lg mt-6">
|
|
||||||
<form class="space-y-6">
|
|
||||||
<div>
|
|
||||||
<label>Name</label> <br>
|
|
||||||
<input type="text" placeholder="Your full name"
|
|
||||||
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>E-mail</label> <br>
|
|
||||||
<input type="email" placeholder="Your e-mail adress"
|
|
||||||
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>Password</label> <br>
|
|
||||||
<input type="password" placeholder="Your password"
|
|
||||||
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>Repeat Password</label> <br>
|
|
||||||
<input type="password" placeholder="Repeat your password"
|
|
||||||
class="w-full mt-2 py-4 px-6 border border-gray-200 rounded-lg">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button class="py-4 px-6 bg-purple-600 text-white rounded-lg">Sign up</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-app>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { RouterLink } from "vue-router";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
@@ -4,7 +4,16 @@
|
|||||||
<div class="px-4"
|
<div class="px-4"
|
||||||
:style="{ backgroundColor: brandingStore.colors.primary, color: brandingStore.colors.onPrimary}">
|
:style="{ backgroundColor: brandingStore.colors.primary, color: brandingStore.colors.onPrimary}">
|
||||||
<h1>TEST</h1>
|
<h1>TEST</h1>
|
||||||
<p>GET ME AN EDITOR NOW!</p>
|
|
||||||
|
<p>MODE: {{ envv }}</p>
|
||||||
|
<p>VITE_API_URL: {{ enva }}</p>
|
||||||
|
<p>VITE_STRIPE_API_KEY: {{ envb }}</p>
|
||||||
|
|
||||||
|
<donation-button :creator-id="creatorId"
|
||||||
|
:creator-name="creatorName"
|
||||||
|
:on-success-url="successUrl"
|
||||||
|
:on-cancelled-url="cancelledUrl"
|
||||||
|
></donation-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -14,9 +23,24 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||||
|
import DonationButton from "@/views/creators/DonationButton.vue";
|
||||||
|
import {computed} from "vue";
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const creatorSlug = route.params.creator_slug || route.path.split('/')[1];
|
||||||
|
const successUrl = `${baseUrl}/${creatorSlug}`
|
||||||
|
const cancelledUrl = `${baseUrl}/${creatorSlug}`
|
||||||
|
|
||||||
const brandingStore = useBrandingStore()
|
const brandingStore = useBrandingStore()
|
||||||
|
const envv = import.meta.env.MODE
|
||||||
|
const enva = import.meta.env.VITE_API_URL
|
||||||
|
const envb = import.meta.env.VITE_STRIPE_API_KEY
|
||||||
|
|
||||||
|
const creatorId = computed(() => brandingStore.value.id)
|
||||||
|
const creatorName = computed(() => brandingStore.value.name)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="tipAmount"
|
v-model="tipAmountInDollars"
|
||||||
type="number"
|
type="number"
|
||||||
:min="0"
|
:min="0"
|
||||||
class="p-2"
|
class="p-2"
|
||||||
@@ -67,8 +67,9 @@
|
|||||||
<div id="checkout">
|
<div id="checkout">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<v-card-actions>
|
||||||
<v-btn block class="ma-auto"
|
<v-btn block class="ma-auto"
|
||||||
style="width: 200px;"
|
style="width: 200px;"
|
||||||
@click="closeDialog()">Annuler
|
@click="closeDialog()">Annuler
|
||||||
@@ -89,6 +90,10 @@ import {useBrandingStore} from "@/stores/brandingStore.js";
|
|||||||
const brandingStore = useBrandingStore()
|
const brandingStore = useBrandingStore()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
creatorId: {default: 'missing-creator-id', required: true},
|
||||||
|
creatorName: {default: 'missing-creator-name', required: true},
|
||||||
|
onSuccessUrl: {default: 'missing-on-success-u', required: true},
|
||||||
|
onCancelledUrl: {default: 'missing-on-cancelled-url', required: true},
|
||||||
iconColorClass: {default: 'text-black'}
|
iconColorClass: {default: 'text-black'}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ function closeDonationDialog() {
|
|||||||
|
|
||||||
const isPaymentDialogActive = ref(false);
|
const isPaymentDialogActive = ref(false);
|
||||||
|
|
||||||
const tipAmount = ref(0);
|
const tipAmountInDollars = ref(0);
|
||||||
const tipMessage = ref("");
|
const tipMessage = ref("");
|
||||||
|
|
||||||
let stripe = null;
|
let stripe = null;
|
||||||
@@ -116,23 +121,21 @@ onMounted(async () => {
|
|||||||
stripe = await loadStripe(import.meta.env.VITE_STRIPE_API_KEY);
|
stripe = await loadStripe(import.meta.env.VITE_STRIPE_API_KEY);
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchClientSecret = async () => {
|
|
||||||
const clientSecret = await createCheckoutSession();
|
|
||||||
return clientSecret;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
async function createCheckoutSession() {
|
async function createCheckoutSession() {
|
||||||
const client = useClient()
|
const client = useClient()
|
||||||
let clientSecret = await client.post('/api/Stripe', {
|
|
||||||
amount: (tipAmount.value * 100),
|
|
||||||
tipMessage: tipMessage.value,
|
|
||||||
creatorId: props.creatorId
|
|
||||||
|
|
||||||
|
let clientSecret = await client.post(
|
||||||
|
`/api/tips`,
|
||||||
|
{
|
||||||
|
amount: tipAmountInDollars.value * 100,
|
||||||
|
currency: 'CAD',
|
||||||
|
message: tipMessage.value,
|
||||||
|
creatorId: props.creatorId,
|
||||||
|
checkoutSuccessUrl: props.onSuccessUrl,
|
||||||
|
checkoutCancelledUrl: props.onCancelledUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
let secret = clientSecret["data"];
|
return clientSecret.data;
|
||||||
return secret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
@@ -145,11 +148,10 @@ function closeDialog() {
|
|||||||
async function goPay() {
|
async function goPay() {
|
||||||
isPaymentDialogActive.value = true;
|
isPaymentDialogActive.value = true;
|
||||||
|
|
||||||
checkout = await stripe.initEmbeddedCheckout({
|
const response = await createCheckoutSession()
|
||||||
fetchClientSecret,
|
|
||||||
});
|
|
||||||
|
|
||||||
await checkout.mount('#checkout');
|
// Redirect to the Stripe Checkout page
|
||||||
|
window.location.href = response.stripeCheckoutUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
function preventNonNumeric(event) {
|
function preventNonNumeric(event) {
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {computed, ref} from "vue";
|
|
||||||
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
|
||||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
|
||||||
|
|
||||||
const brandingStore = useBrandingStore()
|
|
||||||
const subscriptionStore = useSubscriptionStore();
|
|
||||||
|
|
||||||
const isSubscribe = computed(() => !subscriptionStore.isSubscribeTo(brandingStore.value.id));
|
|
||||||
|
|
||||||
function subscribeToCreator() {
|
|
||||||
subscriptionStore.subscribeTo(brandingStore.value.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Référence pour contrôler l'affichage du modal
|
|
||||||
const showUnsubscribeModal = ref(false);
|
|
||||||
|
|
||||||
function unsubscribeFromCreator() {
|
|
||||||
subscriptionStore.unsubscribeFrom(brandingStore.value.id);
|
|
||||||
// Fermer le modal après désabonnement
|
|
||||||
showUnsubscribeModal.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<template v-if="isSubscribe">
|
|
||||||
<v-btn
|
|
||||||
:style="{
|
|
||||||
width: '150px',
|
|
||||||
height: '28px',
|
|
||||||
backgroundColor: brandingStore.colors.secondary,
|
|
||||||
color: 'white',
|
|
||||||
borderRadius: '8px 0 0 8px',
|
|
||||||
padding: '10px 24px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
transition: 'background-color 0.3s ease'
|
|
||||||
}"
|
|
||||||
@click="subscribeToCreator"
|
|
||||||
>
|
|
||||||
<div>Follow</div>
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else>
|
|
||||||
<v-btn
|
|
||||||
:style="{
|
|
||||||
width: '150px',
|
|
||||||
height: '28px',
|
|
||||||
backgroundColor: brandingStore.colors.secondary,
|
|
||||||
color: 'white',
|
|
||||||
borderRadius: '8px 0 0 8px',
|
|
||||||
padding: '10px 24px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
transition: 'background-color 0.3s ease'
|
|
||||||
}"
|
|
||||||
@click="showUnsubscribeModal = true"
|
|
||||||
>
|
|
||||||
<div>{{ $t('subscribebutton.unsubscribe') }}</div>
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<v-dialog v-model="showUnsubscribeModal" max-width="500">
|
|
||||||
<v-card class="text-center rounded-xl"
|
|
||||||
:style="{ border: `3px solid ${brandingStore.colors.secondary}` }">
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between py-4 text-2xl font-bold border-b mb-2">
|
|
||||||
<div class="flex-1 text-center">
|
|
||||||
Déabonnement
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<v-card-title>Confirmation</v-card-title>
|
|
||||||
<v-card-text>Êtes-vous sûr de vouloir vous désabonner ?</v-card-text>
|
|
||||||
<v-card-actions class="justify-center px-4 pb-4">
|
|
||||||
<v-btn text class="flex-grow-1" variant="outlined"
|
|
||||||
:style="{ backgroundColor: 'rgba(255, 255, 255, 0.1)', color: 'rgba(0, 0, 0, 0.4)' }"
|
|
||||||
@click="unsubscribeFromCreator">Oui
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
<v-btn class="flex-grow-1"
|
|
||||||
:style="{ borderColor: brandingStore.colors.secondary, color: brandingStore.colors.secondary }"
|
|
||||||
variant="outlined"
|
|
||||||
@click="showUnsubscribeModal = false">
|
|
||||||
<div :style="{ color: brandingStore.colors.secondary }">Non</div>
|
|
||||||
</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@@ -2,14 +2,17 @@
|
|||||||
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const brandingStore = useBrandingStore()
|
const brandingStore = useBrandingStore()
|
||||||
const subscriptionStore = useSubscriptionStore()
|
const subscriptionStore = useSubscriptionStore()
|
||||||
|
|
||||||
const isSubscribe = computed(() => !subscriptionStore.isSubscribeTo(brandingStore.value.id));
|
const isSubscribe = computed(() => !subscriptionStore.isSubscribeTo(brandingStore.value.id));
|
||||||
|
|
||||||
function subscribeToCreator() {
|
function subscribeToCreator() {
|
||||||
subscriptionStore.subscribeTo(brandingStore.value.id);
|
const target = `@${brandingStore.currentBrand}/subscription`;
|
||||||
|
router.push(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Référence pour contrôler l'affichage du modal
|
// Référence pour contrôler l'affichage du modal
|
||||||
@@ -30,7 +33,7 @@ function unsubscribeFromCreator() {
|
|||||||
height: '28px',
|
height: '28px',
|
||||||
backgroundColor: brandingStore.colors.secondary,
|
backgroundColor: brandingStore.colors.secondary,
|
||||||
color: 'white',
|
color: 'white',
|
||||||
borderRadius: '0 8px 8px 0',
|
borderRadius: '8px',
|
||||||
padding: '10px 24px',
|
padding: '10px 24px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const subscriptionStore = useSubscriptionStore()
|
|||||||
|
|
||||||
<div class="flex items-center content-center font-sans font-semibold pt-2 ">
|
<div class="flex items-center content-center font-sans font-semibold pt-2 ">
|
||||||
<img
|
<img
|
||||||
:src="subscription.creatorPortraitUrl ? subscription.creatorPortraitUrl: '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png' "
|
:src="subscription.creatorPortraitUrl"
|
||||||
alt="Profile Image"
|
alt="Profile Image"
|
||||||
class="rounded-full mx-2"
|
class="rounded-full mx-2"
|
||||||
width="32px"
|
width="32px"
|
||||||
|
|||||||
@@ -1,82 +1,90 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||||
import { ref } from 'vue';
|
import {ref, onMounted} from 'vue';
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
|
||||||
const branding = useBrandingStore();
|
const router = useRouter()
|
||||||
const selectedTier = ref(null);
|
const brandingStore = useBrandingStore();
|
||||||
const tiers = ref([
|
|
||||||
{
|
const tiers = ref([]);
|
||||||
id: 1,
|
|
||||||
name: 'Les Visionnaires',
|
// Fetch tiers from API
|
||||||
description: 'Container blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablalContainer blablal HtmlContainer blablal HtmlContainer blablal...',
|
async function fetchTiers() {
|
||||||
price: 15,
|
const client = useClient()
|
||||||
},
|
const response = await client.get(
|
||||||
]);
|
`/api/membership/tiers/${brandingStore.value.id}`
|
||||||
|
);
|
||||||
|
tiers.value = response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch tiers when the component is mounted
|
||||||
|
onMounted(() => {
|
||||||
|
fetchTiers();
|
||||||
|
});
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
|
|
||||||
const onPrimary = { color: branding.colors.onPrimary}
|
const onPrimary = {color: brandingStore.colors.onPrimary}
|
||||||
const Primary = { backgroundColor: branding.colors.primary}
|
const Primary = {backgroundColor: brandingStore.colors.primary}
|
||||||
|
|
||||||
const onSecondaryColor = { color: branding.colors.onSecondary}
|
const onSecondaryColor = {color: brandingStore.colors.onSecondary}
|
||||||
const secondaryColor = { backgroundColor: branding.colors.secondary}
|
const secondaryColor = {backgroundColor: brandingStore.colors.secondary}
|
||||||
|
|
||||||
function selectTier(id) {
|
const route = useRoute()
|
||||||
selectedTier.value = id;
|
const baseUrl = window.location.origin;
|
||||||
|
const creatorSlug = route.params.creator_slug || route.path.split('/')[1];
|
||||||
|
const successUrl = `${baseUrl}/${creatorSlug}/content`
|
||||||
|
const cancelledUrl = `${baseUrl}/${creatorSlug}`
|
||||||
|
|
||||||
|
async function doSubscribe(tier) {
|
||||||
|
try {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.post(
|
||||||
|
`/api/membership/subscribe`,
|
||||||
|
{
|
||||||
|
creatorId: brandingStore.value.id,
|
||||||
|
tierId: tier.id,
|
||||||
|
checkoutSuccessUrl: successUrl, // TODO: ensure the success-url will insert subscription
|
||||||
|
checkoutCancelledUrl: cancelledUrl
|
||||||
|
})
|
||||||
|
|
||||||
|
window.location.href = response.data.stripeCheckoutUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading subscriptions:", error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container class="d-flex justify-center">
|
<v-container class="d-flex justify-center">
|
||||||
<v-row justify="center">
|
<v-row justify="center">
|
||||||
<!-- Tiers -->
|
|
||||||
<v-col
|
<v-col
|
||||||
:cols="12 / Math.min(tiers.length, 3)"
|
:cols="12 / Math.min(tiers.length, 3)"
|
||||||
md="4"
|
md="4"
|
||||||
v-for="tier in tiers"
|
v-for="tier in tiers"
|
||||||
:key="tier.id"
|
:key="tier.id"
|
||||||
>
|
>
|
||||||
|
<v-btn @click="doSubscribe(tier)" variant="text">
|
||||||
<div class="bg-white shadow-2xl rounded-2xl">
|
<div class="bg-white shadow-2xl rounded-2xl">
|
||||||
<v-img src="/images/hutopymedia/loginpage/loginhutopy.png" class="rounded-t-2xl"></v-img>
|
<v-img src="/images/hutopymedia/loginpage/loginhutopy.png" class="rounded-t-2xl"></v-img>
|
||||||
<div class="pa-6" :style="[Primary, onPrimary]">
|
<div class="pa-6" :style="[Primary, onPrimary]">
|
||||||
<v-card-title class="text-h4 text-center py-4 ">{{ tier.name }}</v-card-title>
|
<v-card-title class="text-h4 text-center py-4 ">{{ tier.name }}</v-card-title>
|
||||||
|
|
||||||
<div class="text-justify">{{ tier.description }}</div>
|
<div class="text-justify">{{ tier.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center bg-fuchsia-800 py-10" :style="[Primary]">
|
|
||||||
<v-btn
|
|
||||||
class="mx-auto"
|
|
||||||
width="200px"
|
|
||||||
@click="selectTier(tier.id)"
|
|
||||||
:style="{
|
|
||||||
backgroundColor: selectedTier === tier.id ? branding.colors.background : branding.colors.secondary,
|
|
||||||
color: selectedTier === tier.id ? branding.colors.onPrimary : branding.colors.onSecondary
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ selectedTier === tier.id ? 'Sélectionné' : 'Choisir' }}
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<v-card-text class="text-center rounded-b-2xl" :style="[secondaryColor, onSecondaryColor]">
|
<v-card-text class="text-center rounded-b-2xl" :style="[secondaryColor, onSecondaryColor]">
|
||||||
<span class="text-h5">{{ tier.price }} $ / par mois</span>
|
<span class="text-h5">{{ tier.price }} $ / par mois</span>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</div>
|
</div>
|
||||||
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
<v-card-actions class="d-flex justify-center mt-10">
|
|
||||||
<v-btn
|
|
||||||
:style="{ backgroundColor: branding.colors.secondary, color: branding.colors.onBackground }"
|
|
||||||
width="250px"
|
|
||||||
variant="elevated"
|
|
||||||
>
|
|
||||||
Payer
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
|
|
||||||
</v-card-actions>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Follow and Subscribe Buttons -->
|
<!-- Follow and Subscribe Buttons -->
|
||||||
<div class="flex flex-row space-x-1 justify-center mt-3 mb-2">
|
<div class="flex flex-row space-x-1 justify-center mt-3 mb-2">
|
||||||
<follow-button></follow-button>
|
|
||||||
<subscribe-button></subscribe-button>
|
<subscribe-button></subscribe-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -150,7 +149,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref, onMounted} from 'vue';
|
import {ref, onMounted} from 'vue';
|
||||||
import SubscribeButton from "@/views/creators/SubscribeButton.vue";
|
import SubscribeButton from "@/views/creators/SubscribeButton.vue";
|
||||||
import FollowButton from "@/views/creators/FollowButton.vue";
|
|
||||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||||
|
|
||||||
const brandingStore = useBrandingStore()
|
const brandingStore = useBrandingStore()
|
||||||
|
|||||||
@@ -1,673 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!--PC -->
|
|
||||||
<div class="hutopy-backgroud-color">
|
|
||||||
|
|
||||||
<div class="flex hidden-xs flex-col items-center page-margin">
|
|
||||||
|
|
||||||
<img class="h-20"
|
|
||||||
src="/images/hutopymedia/banners/hutopy.png" />
|
|
||||||
|
|
||||||
<v-container class="row-between-logo-text">
|
|
||||||
<v-row>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-col xl="8" lg="11" md="12" sm="12" xs="12">
|
|
||||||
<v-row>
|
|
||||||
<!-- Contact image -->
|
|
||||||
<v-col>
|
|
||||||
<img class="contact-image" src="/images/hutopymedia/contactpage/contactpicture.png">
|
|
||||||
</v-col>
|
|
||||||
<!-- Form Information -->
|
|
||||||
<v-col class="row-joinus">
|
|
||||||
<h1 class="h2-Participez-au-développement">PARTICIPEZ AU DÉVELOPPEMENT</h1>
|
|
||||||
<v-text-field v-model="name" label="Nom" style="color: rgb(107, 0, 101);"></v-text-field>
|
|
||||||
<v-text-field v-model="emailAddress" label="Courriel" style="color: rgb(107, 0, 101);"></v-text-field>
|
|
||||||
<v-textarea v-model="reasonToJoin" style="color: rgb(107, 0, 101)"
|
|
||||||
label="Pourquoi voulez-vous participer au développement?" placeholder="Écrivez votre message ici"
|
|
||||||
rows="3" auto-grow></v-textarea>
|
|
||||||
<v-textarea v-model="socialNetworkAccount" style="color: rgb(107, 0, 101)"
|
|
||||||
label="Avez-vous déjà des comptes sur les réseaux sociaux?" placeholder="Écrivez votre message ici"
|
|
||||||
rows="3" auto-grow></v-textarea>
|
|
||||||
<v-btn @click="sendForm()" style="background-color: rgb(163, 14, 121); color: white; font-weight: bold;"
|
|
||||||
class="mt-4 send-btn" block>Envoyez
|
|
||||||
</v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<!-- Text about joining us -->
|
|
||||||
<v-row>
|
|
||||||
<v-container>
|
|
||||||
<p class="h3-text paragraph">Rejoignez l'aventure
|
|
||||||
Hutopy : une
|
|
||||||
invitation à façonner l'avenir de la création.
|
|
||||||
Vous avez un talent, une passion, une vision ? Hutopy vous ouvre ses portes, non seulement comme
|
|
||||||
plateforme, mais comme une communauté vibrante où chaque créateur devient un architecte de l'utopie
|
|
||||||
collective. Ici, votre art, vos idées, et vos rêves trouvent un espace pour s'épanouir, se partager et
|
|
||||||
inspirer.
|
|
||||||
|
|
||||||
</p>
|
|
||||||
<p class="h3-text paragraph {">
|
|
||||||
Faire partie de Hutopy, c'est embrasser une opportunité unique de monétiser votre créativité,
|
|
||||||
d'élargir
|
|
||||||
votre réseau et de participer à un projet grandiose. C'est le moment de transformer votre passion en
|
|
||||||
profession, d'atteindre un public mondial et de contribuer à un mouvement qui valorise la créativité
|
|
||||||
et
|
|
||||||
l'innovation.
|
|
||||||
</p>
|
|
||||||
<p class="h3-text h3-last-text paragraph {">
|
|
||||||
Pour embarquer dans ce voyage vers la réalisation de vos rêves et rejoindre notre communauté de
|
|
||||||
créateurs
|
|
||||||
visionnaires, nous vous invitons à inscrire vos informations. Partagez avec nous votre courriel et
|
|
||||||
votre
|
|
||||||
numéro de téléphone, et nous vous guiderons à travers chaque étape pour établir votre présence sur
|
|
||||||
Hutopy.
|
|
||||||
Laissez-nous votre marque, et ensemble, construisons un monde où la créativité connaît aucune limite.
|
|
||||||
Votre aventure commence maintenant. Bienvenue dans l'univers Hutopy, où chaque créateur est une étoile
|
|
||||||
dans le ciel de notre utopie partagée.
|
|
||||||
</p>
|
|
||||||
</v-container>
|
|
||||||
</v-row>
|
|
||||||
</v-col>
|
|
||||||
<!-- Offset -->
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Mobile low dimensions -->
|
|
||||||
<div class="hidden-sm-and-up flex-col items-center justify-center">
|
|
||||||
|
|
||||||
<!-- Offset -->
|
|
||||||
<v-spacer style="margin-bottom: 25px;"></v-spacer>
|
|
||||||
|
|
||||||
<!-- Contact image -->
|
|
||||||
<v-img src="/images/hutopymedia/contactpage/contactpicture.png" contain aspect-ratio="16/9"
|
|
||||||
style="clip-path: polygon(0 50%, 100% 0, 100% 80%, 0 100%);" class="Scale-80"></v-img>
|
|
||||||
|
|
||||||
<!-- Title -->
|
|
||||||
<v-row class="labelgroup">
|
|
||||||
<v-col cols="12">
|
|
||||||
<h1 class="h2-Participez-au-développement">PARTICIPEZ AU DÉVELOPPEMENT</h1>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<!-- Form Information -->
|
|
||||||
<v-text-field v-model="name" class="labelsize" label="Nom"
|
|
||||||
style="margin-top: 5%; color: rgb(107, 0, 101);"></v-text-field>
|
|
||||||
<v-text-field v-model="emailAddress" class="labelsize" label="Courriel"
|
|
||||||
style="color: rgb(107, 0, 101);"></v-text-field>
|
|
||||||
<v-textarea v-model="reasonToJoin" class="labelsize" style="color: rgb(107, 0, 101)"
|
|
||||||
label="Pourquoi voulez-vous participer au développement?" placeholder="Écrivez votre message ici" rows="3"
|
|
||||||
auto-grow></v-textarea>
|
|
||||||
<v-textarea v-model="socialNetworkAccount" class="labelsize" style="color: rgb(107, 0, 101)"
|
|
||||||
label="Avez-vous déjà des comptes sur les réseaux sociaux?" placeholder="Écrivez votre message ici" rows="3"
|
|
||||||
auto-grow></v-textarea>
|
|
||||||
<v-btn @click="sendForm()"
|
|
||||||
style="background-color: rgb(163, 14, 121); margin-bottom: 8%; color: white; font-weight: bold;"
|
|
||||||
class="mt-4 send-btn" block>
|
|
||||||
Envoyez
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Text about joining us -->
|
|
||||||
<p class="h3-text paragraph">Rejoignez l'aventure
|
|
||||||
Hutopy : une
|
|
||||||
invitation à façonner l'avenir de la création.
|
|
||||||
Vous avez un talent, une passion, une vision ? Hutopy vous ouvre ses portes, non seulement comme
|
|
||||||
plateforme, mais comme une communauté vibrante où chaque créateur devient un architecte de l'utopie
|
|
||||||
collective. Ici, votre art, vos idées, et vos rêves trouvent un espace pour s'épanouir, se partager et
|
|
||||||
inspirer.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="h3-text paragraph">
|
|
||||||
Faire partie de Hutopy, c'est embrasser une opportunité unique de monétiser votre créativité,
|
|
||||||
d'élargir
|
|
||||||
votre réseau et de participer à un projet grandiose. C'est le moment de transformer votre passion en
|
|
||||||
profession, d'atteindre un public mondial et de contribuer à un mouvement qui valorise la créativité
|
|
||||||
et
|
|
||||||
l'innovation.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="h3-text h3-last-text paragraph">
|
|
||||||
Pour embarquer dans ce voyage vers la réalisation de vos rêves et rejoindre notre communauté de
|
|
||||||
créateurs
|
|
||||||
visionnaires, nous vous invitons à inscrire vos informations. Partagez avec nous votre courriel et
|
|
||||||
votre
|
|
||||||
numéro de téléphone, et nous vous guiderons à travers chaque étape pour établir votre présence sur
|
|
||||||
Hutopy.
|
|
||||||
Laissez-nous votre marque, et ensemble, construisons un monde où la créativité connaît aucune limite.
|
|
||||||
Votre aventure commence maintenant. Bienvenue dans l'univers Hutopy, où chaque créateur est une étoile
|
|
||||||
dans le ciel de notre utopie partagée.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<v-dialog v-model="showModal" max-width="600">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title class="text-center" style="margin-top: 30px; margin-bottom: 40px;">
|
|
||||||
<p style="font-size: 2rem; font-weight: 600">INFORMATIONS REÇU</p>
|
|
||||||
</v-card-title>
|
|
||||||
<v-icon class="mx-auto" style="font-size: 10em; color: #a30e79;">mdi-emoticon-happy</v-icon>
|
|
||||||
<v-card-text style="margin-top: 40px; font-size: 1.3rem; margin-bottom: 50px;" class="text-justify">
|
|
||||||
Merci de vous intéresser à notre projet. Lorsque nous serons prêts, nous vous contacterons afin que vous
|
|
||||||
puissiez vous inscrire en primeur sur la plateforme pour nous aider à la développer. Chaque étape du
|
|
||||||
développement est importante, et nous voulons construire cette plateforme avec vous, pour vous.
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions class="justify-end" style="margin-right: 20px;">
|
|
||||||
<v-btn to="/" size="large" class="text-center" color="primary" text @click="showModal = false">Fermer</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { useClient } from "@/plugins/api.js";
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const client = useClient();
|
|
||||||
const showModal = ref(false);
|
|
||||||
const name = ref("");
|
|
||||||
const emailAddress = ref("");
|
|
||||||
const reasonToJoin = ref("");
|
|
||||||
const socialNetworkAccount = ref("");
|
|
||||||
|
|
||||||
//const firstName = name.value.split(" ")[0];
|
|
||||||
//const lastName = name.value.split(" ")[1];
|
|
||||||
|
|
||||||
async function sendForm() {
|
|
||||||
try {
|
|
||||||
const requestBody = {
|
|
||||||
FirstName: name.value,
|
|
||||||
LastName: name.value,
|
|
||||||
EmailAddress: emailAddress.value,
|
|
||||||
PhoneNumber: "",
|
|
||||||
SocialNetworkAccount: socialNetworkAccount.value,
|
|
||||||
ReasonToJoin: reasonToJoin.value
|
|
||||||
};
|
|
||||||
|
|
||||||
await client.post('/api/JoinUs', requestBody);
|
|
||||||
showModal.value = true;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.hutopy-backgroud-color {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Scale-80 {
|
|
||||||
transform: translateY(-30%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 150px) and (max-width: 598px) {
|
|
||||||
|
|
||||||
.labelgroup {
|
|
||||||
margin-top: -50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
|
|
||||||
width: auto;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
clip-path: polygon(0 30%, 100% 30%, 100% 80%, 0 80%);
|
|
||||||
margin-top: -40%;
|
|
||||||
margin-bottom: -30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
|
|
||||||
height: 70px;
|
|
||||||
margin-left: 5%;
|
|
||||||
margin-top: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
margin-top: 5%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
margin-left: 5%;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-left: 20%;
|
|
||||||
margin-top: 16%;
|
|
||||||
border-radius: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
text-align: justify;
|
|
||||||
|
|
||||||
margin-bottom: 10%;
|
|
||||||
margin-top: 3%;
|
|
||||||
margin-left: 3%;
|
|
||||||
margin-right: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.labelsize {
|
|
||||||
max-width: 95%;
|
|
||||||
margin-left: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (min-width: 599px) and (max-width: 749px) {
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
max-width: 100%;
|
|
||||||
margin-top: 4%;
|
|
||||||
height: 103%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 20%;
|
|
||||||
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 140px;
|
|
||||||
|
|
||||||
min-width: 140px;
|
|
||||||
margin-left: 55%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 1.6rem;
|
|
||||||
margin-top: 10%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
text-align: justify;
|
|
||||||
|
|
||||||
margin-bottom: 4%;
|
|
||||||
margin-top: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin-top: 6%;
|
|
||||||
width: 400px;
|
|
||||||
margin-left: 2%;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (min-width: 750px) and (max-width: 999px) {
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
max-width: 100%;
|
|
||||||
margin-top: 4%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 35%;
|
|
||||||
|
|
||||||
border-radius: 30px;
|
|
||||||
width: auto;
|
|
||||||
min-width: 160px;
|
|
||||||
max-width: 180px;
|
|
||||||
margin-left: 40%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin-top: 10%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
text-align: justify;
|
|
||||||
|
|
||||||
margin-bottom: 4%;
|
|
||||||
margin-top: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin-top: 6%;
|
|
||||||
width: 500px;
|
|
||||||
margin-left: 1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1000px) and (max-width: 1279px) {
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 120px;
|
|
||||||
margin-left: 1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 5%;
|
|
||||||
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 180px;
|
|
||||||
min-width: 175px;
|
|
||||||
margin-left: 30%;
|
|
||||||
margin-top: 37%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 3%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.row-joinus {
|
|
||||||
margin-right: -4%;
|
|
||||||
margin-left: -1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
text-align: justify;
|
|
||||||
margin-right: -4%;
|
|
||||||
margin-bottom: 4%;
|
|
||||||
margin-top: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (min-width: 1280px) and (max-width: 1600px) {
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 165px;
|
|
||||||
margin-left: -2.8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 5%;
|
|
||||||
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 180px;
|
|
||||||
min-width: 175px;
|
|
||||||
margin-left: 53%;
|
|
||||||
margin-top: 45%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.row-between-logo-text {
|
|
||||||
margin-top: 2%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
margin-top: 0%;
|
|
||||||
margin-left: -13%
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 15%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-text {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin-top: 2%;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-last-text {
|
|
||||||
margin-bottom: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-joinus {
|
|
||||||
margin-right: -8%;
|
|
||||||
margin-left: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
margin-right: -6%;
|
|
||||||
margin-left: -7%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (min-width: 1600px) and (max-width: 1919px) {
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 165px;
|
|
||||||
margin-left: -3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 5%;
|
|
||||||
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 180px;
|
|
||||||
min-width: 175px;
|
|
||||||
margin-left: 82%;
|
|
||||||
margin-top: 40%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.row-between-logo-text {
|
|
||||||
margin-top: 2%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
margin-top: 0%;
|
|
||||||
margin-left: -13%
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 15%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-text {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin-top: 2%;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-last-text {
|
|
||||||
margin-bottom: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-joinus {
|
|
||||||
margin-right: -15%;
|
|
||||||
margin-left: -13%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
margin-right: -16%;
|
|
||||||
margin-left: -9%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1920px) and (max-width: 2559px) {
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 160px;
|
|
||||||
margin-left: -4.6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 5%;
|
|
||||||
margin-left: 53%;
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 180px;
|
|
||||||
min-width: 175px;
|
|
||||||
margin-bottom: -15%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn {
|
|
||||||
margin-bottom: 4%;
|
|
||||||
margin-top: -1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-between-logo-text {
|
|
||||||
margin-top: 3%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-row {
|
|
||||||
margin-left: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 15%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-text {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin-top: 2%;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-last-text {
|
|
||||||
margin-bottom: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-joinus {
|
|
||||||
margin-right: -18%;
|
|
||||||
margin-left: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
margin-right: -20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-margin {
|
|
||||||
margin-left: -9%;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 2559px) {
|
|
||||||
|
|
||||||
.hutopy-header-image {
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 180px;
|
|
||||||
margin-left: 3.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-image {
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.5);
|
|
||||||
margin-left: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.home-btn {
|
|
||||||
margin-top: 5%;
|
|
||||||
margin-left: 30%;
|
|
||||||
border-radius: 30px;
|
|
||||||
width: 180px;
|
|
||||||
min-width: 175px;
|
|
||||||
margin-bottom: -15%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn {
|
|
||||||
margin-bottom: 4%;
|
|
||||||
margin-top: -1%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-between-logo-text {
|
|
||||||
margin-top: 3%;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-row {
|
|
||||||
margin-left: 20%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.h2-Participez-au-développement {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 15%;
|
|
||||||
margin-bottom: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-text {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin-top: 2%;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h3-last-text {
|
|
||||||
margin-bottom: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.paragraph {
|
|
||||||
margin-left: 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-margin {
|
|
||||||
margin-left: -5.5%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hidden sm:block" style="height: 40px"></div>
|
|
||||||
<div>
|
|
||||||
<div class="flex flex-col lg:flex-row items-center justify-center">
|
|
||||||
<div class="max-w-[700px] min-w-[300px] mt-14">
|
|
||||||
<img class="rounded-none sm:rounded-2xl sm:w-full mr-8" src="/images/hutopymedia/loginpage/loginhutopy.png" alt="hutopy login">
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center min-w-[300px] sm:min-w-[400px] md:min-w-[500px] lg:min-w-[700px] m-12">
|
|
||||||
<register-form></register-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import RegisterForm from "@/views/main/RegisterForm.vue";
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
const router = useRouter();
|
|
||||||
</script>
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="flex flex-col items-center min-w-[300px] sm:min-w-[400px] md:min-w-[500px] lg:min-w-[700px] m-4">
|
|
||||||
<h1 class="text-center text-2xl font-bold mb-5">Inscription</h1>
|
|
||||||
<div class="w-full h-0.5 mt-4 mb-4" :style="{ backgroundColor: '#A30E79' }"></div>
|
|
||||||
<div class="w-full">
|
|
||||||
<v-text-field
|
|
||||||
v-model="userName"
|
|
||||||
label="Username"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-account"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black mb-4"
|
|
||||||
:rules="[userNameRule]"
|
|
||||||
></v-text-field>
|
|
||||||
<div class="flex flex-wrap justify-between gap-4 mb-4">
|
|
||||||
<v-text-field
|
|
||||||
v-model="firstName"
|
|
||||||
label="Prénom"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-account"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black flex-grow min-w-[250px]"
|
|
||||||
></v-text-field>
|
|
||||||
<v-text-field
|
|
||||||
v-model="lastName"
|
|
||||||
label="Nom"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-account"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black flex-grow min-w-[250px]"
|
|
||||||
></v-text-field>
|
|
||||||
</div>
|
|
||||||
<v-text-field
|
|
||||||
v-model="emailAddress"
|
|
||||||
label="Courriel"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-email"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black mb-4"
|
|
||||||
:error="emailError"
|
|
||||||
:error-messages="emailErrorMessage"
|
|
||||||
:rules="[emailRule]"
|
|
||||||
></v-text-field>
|
|
||||||
<v-text-field
|
|
||||||
v-model="password"
|
|
||||||
label="Mot de passe"
|
|
||||||
:type="showPassword ? 'text' : 'password'"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-lock"
|
|
||||||
append-inner-icon="mdi-eye"
|
|
||||||
@click:append-inner="togglePasswordVisibility"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black mb-4"
|
|
||||||
:rules="[passwordRule]"
|
|
||||||
></v-text-field>
|
|
||||||
<v-text-field
|
|
||||||
v-model="confirmPassword"
|
|
||||||
label="Confirmer mot de passe"
|
|
||||||
:type="showPassword ? 'text' : 'password'"
|
|
||||||
variant="outlined"
|
|
||||||
dense
|
|
||||||
prepend-inner-icon="mdi-lock"
|
|
||||||
append-inner-icon="mdi-eye"
|
|
||||||
@click:append-inner="togglePasswordVisibility"
|
|
||||||
color="transparent"
|
|
||||||
class="text-black mb-4"
|
|
||||||
:rules="[validatePasswordRule]"
|
|
||||||
></v-text-field>
|
|
||||||
<v-btn
|
|
||||||
class="w-full text-center text-white"
|
|
||||||
:style="{ backgroundColor: '#A30E79' }"
|
|
||||||
@click="validateForm"
|
|
||||||
>
|
|
||||||
Créer
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal for errors -->
|
|
||||||
<v-dialog v-model="errorDialog" max-width="500px">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title class="headline">Erreur</v-card-title>
|
|
||||||
<v-card-text>{{ errorMessage }}</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn color="primary" text @click="closeErrorDialog">Fermer</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { useClient } from "@/plugins/api.js";
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const client = useClient();
|
|
||||||
|
|
||||||
const firstName = ref('');
|
|
||||||
const lastName = ref('');
|
|
||||||
const emailAddress = ref('');
|
|
||||||
const password = ref('');
|
|
||||||
const confirmPassword = ref('');
|
|
||||||
const userName = ref('');
|
|
||||||
const showPassword = ref(false);
|
|
||||||
const errorDialog = ref(false);
|
|
||||||
const errorMessage = ref('');
|
|
||||||
const emailError = ref(false);
|
|
||||||
const emailErrorMessage = ref('');
|
|
||||||
|
|
||||||
// Validation regex
|
|
||||||
const userNameRegex = /^[a-zA-Z0-9]+$/;
|
|
||||||
const emailRegex = /.+@.+\..+/;
|
|
||||||
const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{6,}$/;
|
|
||||||
|
|
||||||
// Messages d'erreur
|
|
||||||
const ERROR_MESSAGES = {
|
|
||||||
INVALID_EMAIL: 'E-mail doit être valide',
|
|
||||||
PASSWORD_MISMATCH: 'Les mots de passe ne correspondent pas.',
|
|
||||||
WEAK_PASSWORD: 'Doit contenir 6 caractères, un chiffre, une lettre minuscule, majuscule et un caractère non-alphanumérique.',
|
|
||||||
GENERIC_ERROR: 'Une erreur est survenue. Veuillez réessayer.',
|
|
||||||
INVALID_USERNAME: "Le nom d'utilisateur ne doit contenir que des lettres sans accent et/ou des chiffres.",
|
|
||||||
};
|
|
||||||
|
|
||||||
function togglePasswordVisibility() {
|
|
||||||
showPassword.value = !showPassword.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function passwordRule(password) {
|
|
||||||
if (passwordRegex.test(password)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ERROR_MESSAGES.WEAK_PASSWORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validatePasswordRule(validatePassword) {
|
|
||||||
if (password.value === validatePassword) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ERROR_MESSAGES.PASSWORD_MISMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
function emailRule(email) {
|
|
||||||
if (emailRegex.test(email)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ERROR_MESSAGES.INVALID_EMAIL
|
|
||||||
}
|
|
||||||
|
|
||||||
function userNameRule(userName) {
|
|
||||||
if (userNameRegex.test(userName)){
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return ERROR_MESSAGES.INVALID_USERNAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateForm() {
|
|
||||||
emailError.value = false;
|
|
||||||
emailErrorMessage.value = '';
|
|
||||||
|
|
||||||
if (!emailRegex.test(emailAddress.value)) {
|
|
||||||
emailError.value = true;
|
|
||||||
emailErrorMessage.value = ERROR_MESSAGES.INVALID_EMAIL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userNameRegex.test(userName.value)){
|
|
||||||
showErrorDialog(ERROR_MESSAGES.INVALID_EMAIL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password.value !== confirmPassword.value) {
|
|
||||||
showErrorDialog(ERROR_MESSAGES.PASSWORD_MISMATCH);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!passwordRegex.test(password.value)) {
|
|
||||||
showErrorDialog(ERROR_MESSAGES.WEAK_PASSWORD);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
createUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showErrorDialog(message) {
|
|
||||||
errorMessage.value = message;
|
|
||||||
errorDialog.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeErrorDialog() {
|
|
||||||
errorDialog.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createUser() {
|
|
||||||
try {
|
|
||||||
const userInformation = {
|
|
||||||
FirstName: firstName.value,
|
|
||||||
LastName: lastName.value,
|
|
||||||
EmailAddress: emailAddress.value,
|
|
||||||
UserName: userName.value,
|
|
||||||
Password: password.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
await client.post('/api/Users', userInformation);
|
|
||||||
router.push('/login');
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
showErrorDialog(ERROR_MESSAGES.GENERIC_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
Reference in New Issue
Block a user