code refactoring
This commit is contained in:
parent
9494762e86
commit
4b2b7f9868
@ -1,11 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<article class="news-post">
|
<article class="news-post">
|
||||||
<ImageComp class="news-post__image" @load="imageLoaded" :src="post.photo" :alt="post.title" />
|
<ImageComp
|
||||||
|
class="news-post__image"
|
||||||
|
@load="imageLoaded"
|
||||||
|
:src="post.photo"
|
||||||
|
:alt="post.title"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="news-post__container">
|
<div class="news-post__container">
|
||||||
<HeaderComp>{{ post.title }}</HeaderComp>
|
<HeaderComp>{{ post.title }}</HeaderComp>
|
||||||
|
|
||||||
<MetaComp class="news-post__meta" :id="id" :category="post.category" :tags="post.tags" :published_date="post.published_date" />
|
<MetaComp
|
||||||
|
class="news-post__meta"
|
||||||
|
:id="id"
|
||||||
|
:category="post.category"
|
||||||
|
:tags="post.tags"
|
||||||
|
:published_date="post.published_date"
|
||||||
|
/>
|
||||||
|
|
||||||
<SocialComp
|
<SocialComp
|
||||||
class="news-post__social"
|
class="news-post__social"
|
||||||
@ -25,61 +36,65 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, defineProps, onMounted, ref } from "vue";
|
import { computed, defineProps, onMounted, ref } from 'vue'
|
||||||
// components
|
// components
|
||||||
import CommentsList from "./Comments/CommentsList.vue";
|
import CommentsList from './Comments/CommentsList.vue'
|
||||||
import FooterContainer from "@/components/Footer/FooterContainer.vue";
|
import FooterContainer from '@/components/Footer/FooterContainer.vue'
|
||||||
import MetaComp from "@/components/Common/MetaComp.vue";
|
import MetaComp from '@/components/Common/MetaComp.vue'
|
||||||
import SocialComp from "@/components/Common/SocialComp.vue";
|
import SocialComp from '@/components/Common/SocialComp.vue'
|
||||||
// composables
|
// composables
|
||||||
import { useNewsApi } from "@/composables/api/news";
|
import { useNewsApi } from '@/composables/api/news'
|
||||||
const { fetchPostById } = useNewsApi();
|
const { fetchPostById } = useNewsApi()
|
||||||
// reouter
|
// reouter
|
||||||
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
|
||||||
const props = defineProps(["id"]);
|
const props = defineProps(['id'])
|
||||||
|
|
||||||
const post = ref({ title: "", news_body: "", photo: "", category: 0, tags: [], like: 0, comments_count: 0, views: 0 });
|
const post = ref({
|
||||||
|
title: '',
|
||||||
|
news_body: '',
|
||||||
|
photo: '',
|
||||||
|
category: 0,
|
||||||
|
tags: [],
|
||||||
|
like: 0,
|
||||||
|
comments_count: 0,
|
||||||
|
views: 0
|
||||||
|
})
|
||||||
|
|
||||||
const refComments = ref(null);
|
const refComments = ref(null)
|
||||||
|
|
||||||
const content = computed(() => {
|
const content = computed(() => {
|
||||||
if (post.value.news_body) {
|
return post.value.news_body
|
||||||
let val = "<p>";
|
? `<p>${post.value.news_body.replaceAll('\n', '</p><p>')}</p>`
|
||||||
val += post.value.news_body.replaceAll("\n", "</p><p>");
|
: ''
|
||||||
val += "</p>";
|
})
|
||||||
return val;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(init);
|
onMounted(init)
|
||||||
async function init() {
|
async function init() {
|
||||||
window.scroll(0, 0);
|
window.scroll(0, 0)
|
||||||
let fetchedPost = await fetchPostById(props.id);
|
post.value = await fetchPostById(props.id)
|
||||||
post.value = fetchedPost;
|
document.title = `${post.value.title} - DNR.ONE`
|
||||||
document.title = `${post.value.title} - DNR.ONE`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function imageLoaded() {
|
function imageLoaded() {
|
||||||
if (route.hash) {
|
if (route.hash) {
|
||||||
scrollToComments();
|
scrollToComments()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToComments() {
|
function scrollToComments() {
|
||||||
let el = refComments.value.$el;
|
let el = refComments.value.$el
|
||||||
window.scrollTo({ top: el.offsetTop - 45, behavior: "smooth" });
|
window.scrollTo({ top: el.offsetTop - 45, behavior: 'smooth' })
|
||||||
router.replace({ hash: "", query: route.query });
|
router.replace({ hash: '', query: route.query })
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeRouteUpdate((to, from) => {
|
onBeforeRouteUpdate((to, from) => {
|
||||||
if (to.hash === "#comments" && from.hash !== "#comments") {
|
if (to.hash === '#comments' && from.hash !== '#comments') {
|
||||||
scrollToComments();
|
scrollToComments()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -1,9 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-register" :class="isLogin ? 'login-register--login' : 'login-register--register'">
|
<div
|
||||||
|
class="login-register"
|
||||||
|
:class="isLogin ? 'login-register--login' : 'login-register--register'"
|
||||||
|
>
|
||||||
<form class="login-register__form">
|
<form class="login-register__form">
|
||||||
<input class="login-register__input" v-if="!isLogin" v-model="userData.email" type="email" placeholder="почта" name="email" />
|
<input
|
||||||
<input class="login-register__input" v-model="userData.username" type="text" placeholder="имя пользователя" name="username" />
|
class="login-register__input"
|
||||||
<input class="login-register__input" v-model="userData.password" type="password" placeholder="пароль" name="password" />
|
v-if="!isLogin"
|
||||||
|
v-model="userData.email"
|
||||||
|
type="email"
|
||||||
|
placeholder="почта"
|
||||||
|
name="email"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="login-register__input"
|
||||||
|
v-model="userData.username"
|
||||||
|
type="text"
|
||||||
|
placeholder="имя пользователя"
|
||||||
|
name="username"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="login-register__input"
|
||||||
|
v-model="userData.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="пароль"
|
||||||
|
name="password"
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
class="login-register__input"
|
class="login-register__input"
|
||||||
v-if="!isLogin"
|
v-if="!isLogin"
|
||||||
@ -12,14 +34,30 @@
|
|||||||
placeholder="повторите пароль"
|
placeholder="повторите пароль"
|
||||||
name="password2"
|
name="password2"
|
||||||
/>
|
/>
|
||||||
<ButtonComp class="login-register__button" :value="buttonLabel" @click="submit()" :disabled="pending" />
|
<ButtonComp
|
||||||
|
class="login-register__button"
|
||||||
|
:value="buttonLabel"
|
||||||
|
@click="submit()"
|
||||||
|
:disabled="pending"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="login-register__redirect">
|
<div class="login-register__redirect">
|
||||||
{{ redirectText }}
|
{{ redirectText }}
|
||||||
<router-link class="login-register__redirect-link" v-if="isLogin" to="/user/register" @click="reset()">
|
<router-link
|
||||||
|
class="login-register__redirect-link"
|
||||||
|
v-if="isLogin"
|
||||||
|
to="/user/register"
|
||||||
|
@click="reset()"
|
||||||
|
>
|
||||||
Регистрация
|
Регистрация
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link class="login-register__redirect-link" v-else to="/user/login" @click="reset()">Войти</router-link>
|
<router-link
|
||||||
|
class="login-register__redirect-link"
|
||||||
|
v-else
|
||||||
|
to="/user/login"
|
||||||
|
@click="reset()"
|
||||||
|
>Войти</router-link
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="login-register__notifications">
|
<div class="login-register__notifications">
|
||||||
@ -35,12 +73,26 @@
|
|||||||
class="login-register__notification-icon"
|
class="login-register__notification-icon"
|
||||||
:icon="['far', 'circle-check']"
|
:icon="['far', 'circle-check']"
|
||||||
/>
|
/>
|
||||||
<font-awesome-icon v-else class="login-register__notification-icon" :icon="['far', 'circle-xmark']" />
|
<font-awesome-icon
|
||||||
|
v-else
|
||||||
|
class="login-register__notification-icon"
|
||||||
|
:icon="['far', 'circle-xmark']"
|
||||||
|
/>
|
||||||
<div class="login-register__notification-info">
|
<div class="login-register__notification-info">
|
||||||
<div class="login-register__notification-title" v-html="notification.title"></div>
|
<div
|
||||||
<div class="login-register__notification-text" v-html="notification.text"></div>
|
class="login-register__notification-title"
|
||||||
|
v-html="notification.title"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="login-register__notification-text"
|
||||||
|
v-html="notification.text"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<font-awesome-icon class="login-register__notification-close" icon="xmark" @click="removeNotification(index)" />
|
<font-awesome-icon
|
||||||
|
class="login-register__notification-close"
|
||||||
|
icon="xmark"
|
||||||
|
@click="removeNotification(index)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
@ -48,144 +100,180 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineProps, computed } from "vue";
|
import { ref, defineProps, computed } from 'vue'
|
||||||
import { FieldsContainer, FieldChecks } from "@/js/validator";
|
import { FieldsContainer, FieldChecks } from '@/js/validator'
|
||||||
// composables
|
// composables
|
||||||
import { useUserApi } from "@/composables/api/user";
|
import { useUserApi } from '@/composables/api/user'
|
||||||
const api = useUserApi();
|
const api = useUserApi()
|
||||||
// stores
|
// stores
|
||||||
import { useUser } from "@/stores";
|
import { useUser } from '@/stores'
|
||||||
const userStore = useUser();
|
const userStore = useUser()
|
||||||
// router
|
// router
|
||||||
import { onBeforeRouteLeave, useRouter } from "vue-router";
|
import { onBeforeRouteLeave, useRouter } from 'vue-router'
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
|
||||||
const props = defineProps(["type"]);
|
const props = defineProps(['type'])
|
||||||
|
|
||||||
const userData = ref({
|
const userData = ref({
|
||||||
email: "",
|
email: '',
|
||||||
username: "",
|
username: '',
|
||||||
password: "",
|
password: '',
|
||||||
password2: "",
|
password2: ''
|
||||||
});
|
})
|
||||||
|
|
||||||
const notifications = ref([]);
|
const notifications = ref([])
|
||||||
const pending = ref(false);
|
const pending = ref(false)
|
||||||
|
|
||||||
const isLogin = computed(() => props.type === "login");
|
const isLogin = computed(() => props.type === 'login')
|
||||||
const buttonLabel = computed(() => (isLogin.value ? "Войти" : "Регистрация"));
|
const buttonLabel = computed(() => (isLogin.value ? 'Войти' : 'Регистрация'))
|
||||||
const redirectText = computed(() => (isLogin.value ? "Нет аккаунта?" : "Уже есть аккаунт?"));
|
const redirectText = computed(() =>
|
||||||
|
isLogin.value ? 'Нет аккаунта?' : 'Уже есть аккаунт?'
|
||||||
|
)
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
notifications.value = [];
|
notifications.value = []
|
||||||
let errors = getFieldsErrors();
|
let errors = getFieldsErrors()
|
||||||
if (errors.length == 0) {
|
if (errors.length == 0) {
|
||||||
if (isLogin.value) {
|
if (isLogin.value) {
|
||||||
login();
|
login()
|
||||||
} else {
|
} else {
|
||||||
register();
|
register()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
for (let i = 0; i < errors.length; i++) {
|
for (let i = 0; i < errors.length; i++) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notifications.value.push({ type: "error", title: errors[i].title, text: errors[i].text });
|
notifications.value.push({
|
||||||
}, i * 50);
|
type: 'error',
|
||||||
|
title: errors[i].title,
|
||||||
|
text: errors[i].text
|
||||||
|
})
|
||||||
|
}, i * 50)
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFieldsErrors() {
|
function getFieldsErrors() {
|
||||||
const container = new FieldsContainer();
|
const container = new FieldsContainer()
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value) {
|
||||||
container.addField("почта", userData.value.email, [FieldChecks.nonEmpty, FieldChecks.email]);
|
container.addField('почта', userData.value.email, [
|
||||||
|
FieldChecks.nonEmpty,
|
||||||
|
FieldChecks.email
|
||||||
|
])
|
||||||
}
|
}
|
||||||
container.addField("имя пользователя", userData.value.username, [
|
container.addField('имя пользователя', userData.value.username, [
|
||||||
FieldChecks.nonEmpty,
|
FieldChecks.nonEmpty,
|
||||||
FieldChecks.onlyLettersNumbersUnderscores,
|
FieldChecks.onlyLettersNumbersUnderscores,
|
||||||
FieldChecks.minLength(4),
|
FieldChecks.minLength(4),
|
||||||
FieldChecks.maxLength(20),
|
FieldChecks.maxLength(20)
|
||||||
]);
|
])
|
||||||
container.addField("пароль", userData.value.password, [FieldChecks.nonEmpty, FieldChecks.minLength(6), FieldChecks.maxLength(32)]);
|
container.addField('пароль', userData.value.password, [
|
||||||
|
FieldChecks.nonEmpty,
|
||||||
|
FieldChecks.minLength(6),
|
||||||
|
FieldChecks.maxLength(32)
|
||||||
|
])
|
||||||
|
|
||||||
let errors = [];
|
let errors = []
|
||||||
for (let key in container.fields) {
|
for (let key in container.fields) {
|
||||||
let error = container.fields[key].tryGetFirstError();
|
let error = container.fields[key].tryGetFirstError()
|
||||||
if (error !== "") {
|
if (error !== '') {
|
||||||
errors.push({ title: key, text: error });
|
errors.push({ title: key, text: error })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value) {
|
||||||
if (userData.value.password !== userData.value.password2) {
|
if (userData.value.password !== userData.value.password2) {
|
||||||
errors.push({ title: "пароль", text: "пароли не совпадают" });
|
errors.push({ title: 'пароль', text: 'пароли не совпадают' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errors;
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login() {
|
async function login() {
|
||||||
if (pending.value) return;
|
if (pending.value) return
|
||||||
pending.value = true;
|
pending.value = true
|
||||||
|
|
||||||
let resp = await api.login({ username: userData.value.username, password: userData.value.password });
|
let resp = await api.login({
|
||||||
|
username: userData.value.username,
|
||||||
|
password: userData.value.password
|
||||||
|
})
|
||||||
if (resp.hasErrors) {
|
if (resp.hasErrors) {
|
||||||
for (let key in resp.error) {
|
for (let key in resp.error) {
|
||||||
notifications.value.push({ type: "error", title: key, text: resp.error[key][0] });
|
notifications.value.push({
|
||||||
|
type: 'error',
|
||||||
|
title: key,
|
||||||
|
text: resp.error[key][0]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userStore.setUserData(resp.data);
|
userStore.setUserData(resp.data)
|
||||||
userStore.saveUserData();
|
userStore.saveUserData()
|
||||||
|
|
||||||
notifications.value.push({ type: "success", title: "вход", text: "Вход выполнен успешно." });
|
notifications.value.push({
|
||||||
redirectAfterTimeout();
|
type: 'success',
|
||||||
|
title: 'вход',
|
||||||
|
text: 'Вход выполнен успешно.'
|
||||||
|
})
|
||||||
|
redirectAfterTimeout()
|
||||||
}
|
}
|
||||||
pending.value = false;
|
pending.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function register() {
|
async function register() {
|
||||||
if (pending.value) return;
|
if (pending.value) return
|
||||||
pending.value = true;
|
pending.value = true
|
||||||
|
|
||||||
let resp = await api.register({ email: userData.value.email, username: userData.value.username, password: userData.value.password });
|
let resp = await api.register({
|
||||||
|
email: userData.value.email,
|
||||||
|
username: userData.value.username,
|
||||||
|
password: userData.value.password
|
||||||
|
})
|
||||||
if (resp.hasErrors) {
|
if (resp.hasErrors) {
|
||||||
for (let key in resp) {
|
for (let key in resp) {
|
||||||
notifications.value.push({ type: "error", title: key, text: resp.error[key][0] });
|
notifications.value.push({
|
||||||
|
type: 'error',
|
||||||
|
title: key,
|
||||||
|
text: resp.error[key][0]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userStore.setUserData(resp.data);
|
userStore.setUserData(resp.data)
|
||||||
userStore.saveUserData();
|
userStore.saveUserData()
|
||||||
|
|
||||||
notifications.value.push({ type: "success", title: "регистрация", text: "Регистрация прошла успешно." });
|
notifications.value.push({
|
||||||
redirectAfterTimeout();
|
type: 'success',
|
||||||
|
title: 'регистрация',
|
||||||
|
text: 'Регистрация прошла успешно.'
|
||||||
|
})
|
||||||
|
redirectAfterTimeout()
|
||||||
}
|
}
|
||||||
pending.value = false;
|
pending.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
userData.value = {
|
userData.value = {
|
||||||
email: "",
|
email: '',
|
||||||
username: "",
|
username: '',
|
||||||
password: "",
|
password: '',
|
||||||
password2: "",
|
password2: ''
|
||||||
};
|
}
|
||||||
notifications.value = [];
|
notifications.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeNotification(index) {
|
function removeNotification(index) {
|
||||||
notifications.value.splice(index, 1);
|
notifications.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function redirectAfterTimeout() {
|
function redirectAfterTimeout() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push("/");
|
router.push('/')
|
||||||
}, 1000);
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeRouteLeave(() => {
|
onBeforeRouteLeave(() => {
|
||||||
reset();
|
reset()
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -196,7 +284,7 @@ onBeforeRouteLeave(() => {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-top: 25px;
|
padding-top: 25px;
|
||||||
color: color("second");
|
color: color('second');
|
||||||
|
|
||||||
&__form {
|
&__form {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -219,7 +307,7 @@ onBeforeRouteLeave(() => {
|
|||||||
|
|
||||||
&-link {
|
&-link {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
color: color("second");
|
color: color('second');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +338,7 @@ onBeforeRouteLeave(() => {
|
|||||||
gap: 5px;
|
gap: 5px;
|
||||||
padding: 5px 5px;
|
padding: 5px 5px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
border: 1px solid color("border");
|
border: 1px solid color('border');
|
||||||
|
|
||||||
&-icon {
|
&-icon {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
@ -285,13 +373,13 @@ onBeforeRouteLeave(() => {
|
|||||||
|
|
||||||
&--error {
|
&--error {
|
||||||
#{$p}-icon {
|
#{$p}-icon {
|
||||||
color: color("warn");
|
color: color('warn');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--success {
|
&--success {
|
||||||
#{$p}-icon {
|
#{$p}-icon {
|
||||||
color: color("success");
|
color: color('success');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user