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 LoginView from '../views/LoginView.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 Wallet from '../views/main/Wallet.vue'
|
||||
import ProfilePage from '@/views/profile/ProfilePage.vue'
|
||||
@@ -118,22 +115,6 @@ const routes = [
|
||||
path: '/content/post',
|
||||
component: PostContent,
|
||||
},
|
||||
|
||||
{
|
||||
path: '/join',
|
||||
name: 'join',
|
||||
component: Join
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
name: 'register',
|
||||
component: Register
|
||||
},
|
||||
{
|
||||
path: '/signup',
|
||||
name: 'signup',
|
||||
component: SignupView
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
import {useSessionStorage} from "@vueuse/core";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import {watch} from "vue";
|
||||
import {watch, onMounted} from "vue";
|
||||
|
||||
export const useSubscriptionStore = defineStore(
|
||||
'subscription',
|
||||
() => {
|
||||
|
||||
const subscriptions = useSessionStorage(
|
||||
'subscription-subscriptions',
|
||||
{})
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const authWatcher = watch(
|
||||
|
||||
watch(
|
||||
() => authStore.isAuthenticated,
|
||||
async (newValue) => {
|
||||
if (newValue) {
|
||||
@@ -23,42 +20,22 @@ export const useSubscriptionStore = defineStore(
|
||||
}
|
||||
})
|
||||
|
||||
const subscriptions = useSessionStorage(
|
||||
'subscription-subscriptions',
|
||||
{})
|
||||
|
||||
function isSubscribeTo(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() {
|
||||
try {
|
||||
const client = useClient()
|
||||
const response = await client.get(`/api/subscriptions`);
|
||||
const response = await client.get(`/api/membership/active`);
|
||||
|
||||
subscriptions.value = response.data.reduce(
|
||||
(acc, sub) => {
|
||||
acc[sub.creatorId] = sub;
|
||||
acc[sub.creatorId] = sub;
|
||||
return acc;
|
||||
},
|
||||
{});
|
||||
@@ -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>
|
||||
@@ -1,12 +1,21 @@
|
||||
<template>
|
||||
<div class="flex flex-row">
|
||||
|
||||
<div class="px-4"
|
||||
:style="{ backgroundColor: brandingStore.colors.primary, color: brandingStore.colors.onPrimary}">
|
||||
|
||||
<div class="px-4"
|
||||
:style="{ backgroundColor: brandingStore.colors.primary, color: brandingStore.colors.onPrimary}">
|
||||
<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>
|
||||
|
||||
</template>
|
||||
@@ -14,9 +23,24 @@
|
||||
<script setup>
|
||||
|
||||
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 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>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="tipAmount"
|
||||
v-model="tipAmountInDollars"
|
||||
type="number"
|
||||
:min="0"
|
||||
class="p-2"
|
||||
@@ -67,8 +67,9 @@
|
||||
<div id="checkout">
|
||||
</div>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn block class="ma-auto"
|
||||
style="width: 200px;"
|
||||
@click="closeDialog()">Annuler
|
||||
@@ -89,6 +90,10 @@ import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
const brandingStore = useBrandingStore()
|
||||
|
||||
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'}
|
||||
});
|
||||
|
||||
@@ -105,7 +110,7 @@ function closeDonationDialog() {
|
||||
|
||||
const isPaymentDialogActive = ref(false);
|
||||
|
||||
const tipAmount = ref(0);
|
||||
const tipAmountInDollars = ref(0);
|
||||
const tipMessage = ref("");
|
||||
|
||||
let stripe = null;
|
||||
@@ -116,23 +121,21 @@ onMounted(async () => {
|
||||
stripe = await loadStripe(import.meta.env.VITE_STRIPE_API_KEY);
|
||||
});
|
||||
|
||||
const fetchClientSecret = async () => {
|
||||
const clientSecret = await createCheckoutSession();
|
||||
return clientSecret;
|
||||
};
|
||||
|
||||
|
||||
async function createCheckoutSession() {
|
||||
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 secret;
|
||||
return clientSecret.data;
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
@@ -145,11 +148,10 @@ function closeDialog() {
|
||||
async function goPay() {
|
||||
isPaymentDialogActive.value = true;
|
||||
|
||||
checkout = await stripe.initEmbeddedCheckout({
|
||||
fetchClientSecret,
|
||||
});
|
||||
const response = await createCheckoutSession()
|
||||
|
||||
await checkout.mount('#checkout');
|
||||
// Redirect to the Stripe Checkout page
|
||||
window.location.href = response.stripeCheckoutUrl
|
||||
}
|
||||
|
||||
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 {computed, ref} from "vue";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const router = useRouter()
|
||||
const brandingStore = useBrandingStore()
|
||||
const subscriptionStore = useSubscriptionStore()
|
||||
|
||||
const isSubscribe = computed(() => !subscriptionStore.isSubscribeTo(brandingStore.value.id));
|
||||
|
||||
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
|
||||
@@ -30,7 +33,7 @@ function unsubscribeFromCreator() {
|
||||
height: '28px',
|
||||
backgroundColor: brandingStore.colors.secondary,
|
||||
color: 'white',
|
||||
borderRadius: '0 8px 8px 0',
|
||||
borderRadius: '8px',
|
||||
padding: '10px 24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -46,17 +49,17 @@ function unsubscribeFromCreator() {
|
||||
<template v-else>
|
||||
<v-btn
|
||||
:style="{
|
||||
width: '150px',
|
||||
height: '28px',
|
||||
backgroundColor: brandingStore.colors.secondary,
|
||||
color: 'white',
|
||||
borderRadius: '0 8px 8px 0',
|
||||
padding: '10px 24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transition: 'background-color 0.3s ease'
|
||||
}"
|
||||
width: '150px',
|
||||
height: '28px',
|
||||
backgroundColor: brandingStore.colors.secondary,
|
||||
color: 'white',
|
||||
borderRadius: '0 8px 8px 0',
|
||||
padding: '10px 24px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transition: 'background-color 0.3s ease'
|
||||
}"
|
||||
@click="showUnsubscribeModal = true"
|
||||
>
|
||||
<div>{{ $t('subscribebutton.unsubscribe') }}</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ const subscriptionStore = useSubscriptionStore()
|
||||
|
||||
<div class="flex items-center content-center font-sans font-semibold pt-2 ">
|
||||
<img
|
||||
:src="subscription.creatorPortraitUrl ? subscription.creatorPortraitUrl: '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png' "
|
||||
:src="subscription.creatorPortraitUrl"
|
||||
alt="Profile Image"
|
||||
class="rounded-full mx-2"
|
||||
width="32px"
|
||||
|
||||
@@ -1,82 +1,90 @@
|
||||
<script setup>
|
||||
import { useBrandingStore } from "@/stores/brandingStore.js";
|
||||
import { ref } from 'vue';
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import {ref, onMounted} from 'vue';
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
|
||||
const branding = useBrandingStore();
|
||||
const selectedTier = ref(null);
|
||||
const tiers = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Les Visionnaires',
|
||||
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...',
|
||||
price: 15,
|
||||
},
|
||||
]);
|
||||
const router = useRouter()
|
||||
const brandingStore = useBrandingStore();
|
||||
|
||||
const tiers = ref([]);
|
||||
|
||||
// Fetch tiers from API
|
||||
async function fetchTiers() {
|
||||
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
|
||||
|
||||
const onPrimary = { color: branding.colors.onPrimary}
|
||||
const Primary = { backgroundColor: branding.colors.primary}
|
||||
const onPrimary = {color: brandingStore.colors.onPrimary}
|
||||
const Primary = {backgroundColor: brandingStore.colors.primary}
|
||||
|
||||
const onSecondaryColor = { color: branding.colors.onSecondary}
|
||||
const secondaryColor = { backgroundColor: branding.colors.secondary}
|
||||
const onSecondaryColor = {color: brandingStore.colors.onSecondary}
|
||||
const secondaryColor = {backgroundColor: brandingStore.colors.secondary}
|
||||
|
||||
function selectTier(id) {
|
||||
selectedTier.value = id;
|
||||
const route = useRoute()
|
||||
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>
|
||||
|
||||
<template>
|
||||
<v-container class="d-flex justify-center">
|
||||
<v-row justify="center">
|
||||
<!-- Tiers -->
|
||||
|
||||
<v-col
|
||||
:cols="12 / Math.min(tiers.length, 3)"
|
||||
md="4"
|
||||
v-for="tier in tiers"
|
||||
:key="tier.id"
|
||||
>
|
||||
<div class="bg-white shadow-2xl rounded-2xl">
|
||||
<v-img src="/images/hutopymedia/loginpage/loginhutopy.png" class="rounded-t-2xl"></v-img>
|
||||
<div class="pa-6" :style="[Primary, onPrimary]">
|
||||
<v-card-title class="text-h4 text-center py-4 ">{{ tier.name }}</v-card-title>
|
||||
|
||||
<div class="text-justify">{{ tier.description }}</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>
|
||||
|
||||
<v-btn @click="doSubscribe(tier)" variant="text">
|
||||
<div class="bg-white shadow-2xl rounded-2xl">
|
||||
<v-img src="/images/hutopymedia/loginpage/loginhutopy.png" class="rounded-t-2xl"></v-img>
|
||||
<div class="pa-6" :style="[Primary, onPrimary]">
|
||||
<v-card-title class="text-h4 text-center py-4 ">{{ tier.name }}</v-card-title>
|
||||
<div class="text-justify">{{ tier.description }}</div>
|
||||
</div>
|
||||
|
||||
<v-card-text class="text-center rounded-b-2xl" :style="[secondaryColor, onSecondaryColor]">
|
||||
<span class="text-h5">{{ tier.price }} $ / par mois</span>
|
||||
</v-card-text>
|
||||
</div>
|
||||
<v-card-text class="text-center rounded-b-2xl" :style="[secondaryColor,onSecondaryColor]" >
|
||||
<span class="text-h5">{{ tier.price }} $ / par mois </span>
|
||||
</v-card-text>
|
||||
</div>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
</v-row>
|
||||
</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>
|
||||
|
||||
<style scoped>
|
||||
@@ -85,7 +93,7 @@ function selectTier(id) {
|
||||
}
|
||||
|
||||
.dotted-border {
|
||||
border: 2px dotted ;
|
||||
border: 2px dotted;
|
||||
padding: 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
</div>
|
||||
<!-- Follow and Subscribe Buttons -->
|
||||
<div class="flex flex-row space-x-1 justify-center mt-3 mb-2">
|
||||
<follow-button></follow-button>
|
||||
<subscribe-button></subscribe-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -150,7 +149,6 @@
|
||||
<script setup>
|
||||
import {ref, onMounted} from 'vue';
|
||||
import SubscribeButton from "@/views/creators/SubscribeButton.vue";
|
||||
import FollowButton from "@/views/creators/FollowButton.vue";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
|
||||
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