mirror of
https://github.com/creativetimofficial/vue-material-kit.git
synced 2025-05-23 21:04:21 +08:00
commit
a389179d68
@ -29,6 +29,11 @@
|
|||||||
href="https://fonts.googleapis.com/icon?family=Material+Icons+Round"
|
href="https://fonts.googleapis.com/icon?family=Material+Icons+Round"
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
|
<!-- Our CSS -->
|
||||||
|
<link
|
||||||
|
href="./src/assets/css/linkedmin.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -6,4 +6,6 @@
|
|||||||
font-family: SpaceMono;
|
font-family: SpaceMono;
|
||||||
src:url('./fonts/SpaceMono-Regular.ttf') format('truetype') ;
|
src:url('./fonts/SpaceMono-Regular.ttf') format('truetype') ;
|
||||||
}
|
}
|
||||||
|
h1{
|
||||||
|
font-family: 'PressStart2P';
|
||||||
|
}
|
||||||
|
BIN
src/assets/img/ultraviolet.jpg
Normal file
BIN
src/assets/img/ultraviolet.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 MiB |
@ -5,7 +5,7 @@ import { useWindowsWidth } from "../../assets/js/useWindowsWidth";
|
|||||||
|
|
||||||
// images
|
// images
|
||||||
import ArrDark from "@/assets/img/down-arrow-dark.svg";
|
import ArrDark from "@/assets/img/down-arrow-dark.svg";
|
||||||
import downArrow from "@/assets/img/down-arrow.svg";
|
|
||||||
import DownArrWhite from "@/assets/img/down-arrow-white.svg";
|
import DownArrWhite from "@/assets/img/down-arrow-white.svg";
|
||||||
|
|
||||||
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token')); // Computed property to check if the user is authenticated
|
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token')); // Computed property to check if the user is authenticated
|
||||||
@ -278,6 +278,22 @@ watch(
|
|||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isAuthenticated" class="position-relative">
|
||||||
|
<div
|
||||||
|
class="dropdown-header text-dark font-weight-bolder d-flex align-items-center px-1"
|
||||||
|
>
|
||||||
|
Мои проекты
|
||||||
|
</div>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'myprojects' }"
|
||||||
|
class="dropdown-item border-radius-md"
|
||||||
|
>
|
||||||
|
<span>Мои проекты</span>
|
||||||
|
</RouterLink>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -343,9 +359,23 @@ watch(
|
|||||||
Мой Профиль
|
Мой Профиль
|
||||||
</h6>
|
</h6>
|
||||||
<span class="text-sm"
|
<span class="text-sm"
|
||||||
>Рассказ о том, какой я классный</span
|
>Просмотр</span
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
class="dropdown-item py-2 ps-3 border-radius-md"
|
||||||
|
href="/EditMyProfile"
|
||||||
|
>
|
||||||
|
<h6
|
||||||
|
class="dropdown-header text-dark font-weight-bolder d-flex justify-content-cente align-items-center p-0"
|
||||||
|
>
|
||||||
|
Мой Профиль
|
||||||
|
</h6>
|
||||||
|
<span class="text-sm"
|
||||||
|
>Редактирование</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="dropdown-item py-2 ps-3 border-radius-md"
|
class="dropdown-item py-2 ps-3 border-radius-md"
|
||||||
href="/CreateProject"
|
href="/CreateProject"
|
||||||
@ -356,7 +386,7 @@ watch(
|
|||||||
Создать проект
|
Создать проект
|
||||||
</h6>
|
</h6>
|
||||||
<span class="text-sm"
|
<span class="text-sm"
|
||||||
>Чтобы стать ещё более классным</span
|
>Страница добавления проекта</span
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -376,11 +406,39 @@ watch(
|
|||||||
Мой профиль
|
Мой профиль
|
||||||
</h6>
|
</h6>
|
||||||
<span class="text-sm"
|
<span class="text-sm"
|
||||||
>Рассказ о том, какой я классный</span
|
>Просмотр</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="dropdown-item py-2 ps-3 border-radius-md"
|
||||||
|
href="/ViewMyProfile"
|
||||||
|
>
|
||||||
|
<h6
|
||||||
|
class="dropdown-header text-dark font-weight-bolder d-flex justify-content-cente align-items-center p-0"
|
||||||
|
>
|
||||||
|
Мой профиль
|
||||||
|
</h6>
|
||||||
|
<span class="text-sm"
|
||||||
|
>Редактирование</span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="dropdown-item py-2 ps-3 border-radius-md"
|
||||||
|
href="/CreateProject"
|
||||||
|
>
|
||||||
|
<h6
|
||||||
|
class="dropdown-header text-dark font-weight-bolder d-flex justify-content-cente align-items-center p-0"
|
||||||
|
>
|
||||||
|
Создать проект
|
||||||
|
</h6>
|
||||||
|
<span class="text-sm"
|
||||||
|
>Страница добавления проекта</span
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -15,6 +15,7 @@ import ViewMyProfile from "../views/LandingPages/Profile/AdmireProfile.vue";
|
|||||||
import EditMyProfile from "../views/LandingPages/Profile/EditProfile.vue";
|
import EditMyProfile from "../views/LandingPages/Profile/EditProfile.vue";
|
||||||
import CreateProject from "../views/LandingPages/Project/AddProject.vue";
|
import CreateProject from "../views/LandingPages/Project/AddProject.vue";
|
||||||
import EditProject from "../views/LandingPages/Project/EditProject.vue";
|
import EditProject from "../views/LandingPages/Project/EditProject.vue";
|
||||||
|
import MyProjects from "../views/LandingPages/Project/MyProjects.vue";
|
||||||
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
@ -38,6 +39,12 @@ const router = createRouter({
|
|||||||
component: Projects
|
component: Projects
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/myprojects',
|
||||||
|
name: 'myprojects',
|
||||||
|
component: MyProjects
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/CreateProject',
|
path: '/CreateProject',
|
||||||
name: 'createproject',
|
name: 'createproject',
|
||||||
|
@ -52,6 +52,7 @@ onMounted(async() => {
|
|||||||
<h2>{{ profileData.username }}</h2>
|
<h2>{{ profileData.username }}</h2>
|
||||||
<p>{{ profileData.email }}</p>
|
<p>{{ profileData.email }}</p>
|
||||||
<P>Имя: {{ profileData.name }}</P>
|
<P>Имя: {{ profileData.name }}</P>
|
||||||
|
<img :src="profileData.profile_image" alt="Profile Image">
|
||||||
<p>Местоположение: {{ profileData.location }}</p>
|
<p>Местоположение: {{ profileData.location }}</p>
|
||||||
<p>Краткое описание: {{ profileData.short_intro }}</p>
|
<p>Краткое описание: {{ profileData.short_intro }}</p>
|
||||||
<p>Биография: {{ profileData.bio }}</p>
|
<p>Биография: {{ profileData.bio }}</p>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { onMounted, onUnmounted } from "vue";
|
import { onMounted, onUnmounted } from "vue";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
||||||
|
|
||||||
|
|
||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
@ -29,7 +30,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<NavbarDefault />
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<h2 class="result-header">Найдено людей: {{ searchResultUsers.length}} </h2>
|
<h2 class="result-header">Найдено людей: {{ searchResultUsers.length}} </h2>
|
||||||
@ -37,7 +38,7 @@ onMounted(() => {
|
|||||||
<div class="result-card" v-for="user in searchResultUsers" :key="user.id">
|
<div class="result-card" v-for="user in searchResultUsers" :key="user.id">
|
||||||
<h3>{{ user.username }} with id {{ user.id }}</h3>
|
<h3>{{ user.username }} with id {{ user.id }}</h3>
|
||||||
<p>{{ user.email }}</p>
|
<p>{{ user.email }}</p>
|
||||||
<a :href="`http://somebodyhire.me/profile/${user.id}`">Страница пользователя</a>
|
<a :href="`/profile/${user.id}`">Страница пользователя</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,9 +4,6 @@ import { onMounted, ref, computed } from "vue";
|
|||||||
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token'));
|
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token'));
|
||||||
const userId = computed(() => sessionStorage.getItem('user_id'));
|
const userId = computed(() => sessionStorage.getItem('user_id'));
|
||||||
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
||||||
@ -14,9 +11,8 @@ const token = computed(() => sessionStorage.getItem('access_token'));
|
|||||||
|
|
||||||
const profileData = ref([]);
|
const profileData = ref([]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const debugText = ref('');
|
const debugText = ref('');
|
||||||
|
const selectedImage = ref(null);
|
||||||
|
|
||||||
const getProfile = async () => {
|
const getProfile = async () => {
|
||||||
const profileDataRecieved = await axios.get(`http://somebodyhire.me/api/profile/${userId.value}/`);
|
const profileDataRecieved = await axios.get(`http://somebodyhire.me/api/profile/${userId.value}/`);
|
||||||
@ -25,23 +21,33 @@ const getProfile = async () => {
|
|||||||
|
|
||||||
const processProfileData = (data) => {
|
const processProfileData = (data) => {
|
||||||
return {
|
return {
|
||||||
...data,
|
name: data.name || '',
|
||||||
name: data.name || '🤷 No Name Provided',
|
email: data.email || '',
|
||||||
location: data.location || '🌍 No Location Provided',
|
username: data.username || '',
|
||||||
short_intro: data.short_intro || '📝 No Short Intro Provided',
|
location: data.location || '',
|
||||||
bio: data.bio || '📘 No Bio Provided',
|
short_intro: data.short_intro || '',
|
||||||
profile_image: data.profile_image || '📷 No Image Provided',
|
bio: data.bio || '',
|
||||||
social_github: data.social_github || '👨💻 No Github Provided',
|
social_github: data.social_github || '',
|
||||||
social_twitter: data.social_twitter || '🐦 No Twitter Provided',
|
social_twitter: data.social_twitter || '',
|
||||||
social_vk: data.social_vk || '🔵 No VK Provided',
|
social_vk: data.social_vk || '',
|
||||||
social_youtube: data.social_youtube || '▶️ No YouTube Provided',
|
social_youtube: data.social_youtube || '',
|
||||||
social_website: data.social_website || '🌐 No Website Provided',
|
social_website: data.social_website || '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Axios request and response interceptors
|
|
||||||
axios.interceptors.request.use((request) => {
|
axios.interceptors.request.use((request) => {
|
||||||
debugText.value += '\n\nRequest:\n' + JSON.stringify(request, null, 2);
|
if (request.data instanceof FormData) {
|
||||||
|
const formData = request.data;
|
||||||
|
for (let [key, value] of formData.entries()) {
|
||||||
|
if (value instanceof File) {
|
||||||
|
debugText.value += `\nFile being sent: ${value.name}, size: ${value.size} bytes`;
|
||||||
|
} else {
|
||||||
|
debugText.value += `\n${key}: ${value}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugText.value += '\n\nRequest:\n' + JSON.stringify(request, null, 2);
|
||||||
|
}
|
||||||
return request;
|
return request;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -53,19 +59,37 @@ axios.interceptors.response.use((response) => {
|
|||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateProfile = async () => {
|
const onFileChange = (event) => {
|
||||||
try {
|
selectedImage.value = event.target.files[0];
|
||||||
const token = computed(() => sessionStorage.getItem('access_token'));
|
debugText.value = `Selected image: ${selectedImage.value.name}`;
|
||||||
debugText.value = `Type of token: ${typeof token.value}, Value of token: ${token.value}`;
|
|
||||||
const headers = { 'Authorization': `Bearer ${token.value}` };
|
|
||||||
await axios.put(`http://somebodyhire.me/api/profile/${userId.value}/`, profileData.value, { headers });
|
|
||||||
router.push('/ViewMyProfile');
|
|
||||||
} catch (error) {
|
|
||||||
debugText.value = `Error: ${JSON.stringify(error, null, 2)}`;
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateProfile = async () => {
|
||||||
|
try {
|
||||||
|
const tokenValue = token.value;
|
||||||
|
const headers = {
|
||||||
|
'Authorization': `Bearer ${tokenValue}`,
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new FormData object
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
// Append the profile data
|
||||||
|
Object.entries(profileData.value).forEach(([key, value]) => {
|
||||||
|
formData.append(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Append the image file
|
||||||
|
formData.append('profile_image', selectedImage.value);
|
||||||
|
|
||||||
|
await axios.patch(`http://somebodyhire.me/api/profile/${userId.value}/`, formData, { headers });
|
||||||
|
// router.push('/ViewMyProfile');
|
||||||
|
} catch (error) {
|
||||||
|
debugText.value = `Error: ${JSON.stringify(error, null, 2)}`;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const cancelUpdate = () => {
|
const cancelUpdate = () => {
|
||||||
router.push('/ViewMyProfile');
|
router.push('/ViewMyProfile');
|
||||||
@ -74,42 +98,30 @@ const cancelUpdate = () => {
|
|||||||
onMounted(async() => {
|
onMounted(async() => {
|
||||||
await getProfile();
|
await getProfile();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavbarDefault />
|
<NavbarDefault />
|
||||||
<div class="profile-container">
|
<div class="profile-container">
|
||||||
<h1>Профиль пользователя {{ loggedUserName }}</h1>
|
<h1>User Profile: {{ loggedUserName }}</h1>
|
||||||
<textarea readonly v-model="debugText"></textarea>
|
<textarea readonly v-model="debugText"></textarea>
|
||||||
|
<input type="file" accept="image/*" @change="onFileChange">
|
||||||
<input type="text" v-model="profileData.username" placeholder="Username">
|
<input type="text" v-model="profileData.username" placeholder="Username">
|
||||||
<input type="email" v-model="profileData.email" placeholder="Email">
|
<input type="email" v-model="profileData.email" placeholder="Email">
|
||||||
<input type="text" v-model="profileData.name" placeholder="Имя">
|
<input type="text" v-model="profileData.name" placeholder="Name">
|
||||||
<input type="text" v-model="profileData.short_intro" placeholder="Краткое описание">
|
<input type="text" v-model="profileData.short_intro" placeholder="Short Introduction">
|
||||||
<textarea v-model="profileData.bio" placeholder="Биография"></textarea>
|
<textarea v-model="profileData.bio" placeholder="Biography"></textarea>
|
||||||
<textarea v-model="profileData.profile_image" placeholder="Ссылка на изображение"></textarea>
|
<textarea v-model="profileData.social_github" placeholder="GitHub Link"></textarea>
|
||||||
<textarea v-model="profileData.social_github" placeholder="Ссылка на GitHub"></textarea>
|
<textarea v-model="profileData.social_twitter" placeholder="Twitter Link"></textarea>
|
||||||
<textarea v-model="profileData.social_twitter" placeholder="Ссылка на Twitter"></textarea>
|
<textarea v-model="profileData.social_vk" placeholder="VK Link"></textarea>
|
||||||
<textarea v-model="profileData.social_vk" placeholder="Ссылка на VK"></textarea>
|
<textarea v-model="profileData.social_youtube" placeholder="YouTube Link"></textarea>
|
||||||
<textarea v-model="profileData.social_youtube" placeholder="Ссылка на YouTube"></textarea>
|
<textarea v-model="profileData.social_website" placeholder="Website Link"></textarea>
|
||||||
<textarea v-model="profileData.social_website" placeholder="Ссылка на сайт"></textarea>
|
|
||||||
<button @click="updateProfile" class="btn-submit">Submit</button>
|
<button @click="updateProfile" class="btn-submit">Submit</button>
|
||||||
<button @click="cancelUpdate" class="btn-cancel">Cancel</button>
|
<button @click="cancelUpdate" class="btn-cancel">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.profile-container {
|
.profile-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import NavbarDefault from '../../../examples/navbars/NavbarDefault.vue';
|
||||||
|
|
||||||
const profileId = ref(null);
|
const profileId = ref(null);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -27,17 +27,45 @@ const getProfile = async () => {
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<NavbarDefault />
|
||||||
<h1>Профиль пользователя номер: {{ profileData.id }}</h1>
|
<div class="profile-container">
|
||||||
|
<h1>Профиль пользователя {{ loggedUserName }}</h1>
|
||||||
<h2>{{ profileData.username }}</h2>
|
<h2>{{ profileData.username }}</h2>
|
||||||
<p>{{ profileData.email }}</p>
|
<p>{{ profileData.email }}</p>
|
||||||
|
<P>Имя: {{ profileData.name }}</P>
|
||||||
|
<p>Местоположение: {{ profileData.location }}</p>
|
||||||
|
<p>Краткое описание: {{ profileData.short_intro }}</p>
|
||||||
|
<p>Биография: {{ profileData.bio }}</p>
|
||||||
|
<p>Ссылка на изображение: {{ profileData.profile_image }}</p>
|
||||||
|
<p>Ссылка на GitHub: {{ profileData.social_github }}</p>
|
||||||
|
<p>Ссылка на Twitter: {{ profileData.social_twitter }}</p>
|
||||||
|
<p>Ссылка на VK: {{ profileData.social_vk }}</p>
|
||||||
|
<p>Ссылка на YouTube: {{ profileData.social_youtube }}</p>
|
||||||
|
<p>Ссылка на сайт: {{ profileData.social_website }}</p>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
</style>
|
.profile-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 80%;
|
||||||
|
margin: auto;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-container img {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,7 @@
|
|||||||
import { onMounted, onUnmounted } from "vue";
|
import { onMounted, onUnmounted } from "vue";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
||||||
|
|
||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
const searchResultProjects = ref([]);
|
const searchResultProjects = ref([]);
|
||||||
@ -29,14 +29,14 @@ onMounted(() => {
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<NavbarDefault />
|
||||||
<div>
|
<div>
|
||||||
<h2 class="result-header">Найдено проектов: {{ searchResultProjects.length}} </h2>
|
<h2 class="result-header">Найдено проектов: {{ searchResultProjects.length}} </h2>
|
||||||
<div class="result-grid">
|
<div class="result-grid">
|
||||||
<div class="result-card" v-for="project in searchResultProjects" :key="project.id">
|
<div class="result-card" v-for="project in searchResultProjects" :key="project.id">
|
||||||
<h3>{{ project.title }} with ID {{ project.id }}</h3>
|
<h3>{{ project.title }} with ID {{ project.id }}</h3>
|
||||||
<p>{{ project.description }}</p>
|
<p>{{ project.description }}</p>
|
||||||
<a :href="`http://somebodyhire.me/project/${project.id}`">Страница проекта</a>
|
<a :href="`/project/${project.id}`">Страница проекта</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -0,0 +1,181 @@
|
|||||||
|
<script setup>
|
||||||
|
import axios from 'axios';
|
||||||
|
import { onMounted, ref, computed } from "vue";
|
||||||
|
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token'));
|
||||||
|
const userId = computed(() => sessionStorage.getItem('user_id'));
|
||||||
|
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
||||||
|
const token = computed(() => sessionStorage.getItem('access_token'));
|
||||||
|
|
||||||
|
const projectData = ref([]);
|
||||||
|
const router = useRouter();
|
||||||
|
const debugText = ref('');
|
||||||
|
const projectId = ref(null);
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
|
||||||
|
// const getProfile = async () => {
|
||||||
|
// const profileDataRecieved = await axios.get(`http://somebodyhire.me/api/profile/${userId.value}/`);
|
||||||
|
// profileData.value = processProfileData(profileDataRecieved.data);
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
axios.interceptors.request.use((request) => {
|
||||||
|
debugText.value += '\n\nRequest:\n' + JSON.stringify(request, null, 2);
|
||||||
|
return request;
|
||||||
|
});
|
||||||
|
|
||||||
|
axios.interceptors.response.use((response) => {
|
||||||
|
debugText.value += '\n\nResponse:\n' + JSON.stringify(response, null, 2);
|
||||||
|
return response;
|
||||||
|
}, (error) => {
|
||||||
|
debugText.value += '\n\nResponse Error:\n' + JSON.stringify(error.toJSON(), null, 2);
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getProject = async () => {
|
||||||
|
try {
|
||||||
|
const projectDataRecieved = await axios.get(`http://somebodyhire.me/api/projects/${projectId.value}/`);
|
||||||
|
projectData.value = projectDataRecieved.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('There was an error fetching the project data', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const updateProfile = async () => {
|
||||||
|
// try {
|
||||||
|
// const token = computed(() => sessionStorage.getItem('access_token'));
|
||||||
|
// debugText.value = `Type of token: ${typeof token.value}, Value of token: ${token.value}`;
|
||||||
|
// const headers = { 'Authorization': `Bearer ${token.value}` };
|
||||||
|
// await axios.patch(`http://somebodyhire.me/api/profile/${userId.value}/`, profileData.value, { headers });
|
||||||
|
// router.push('/ViewMyProfile');
|
||||||
|
// } catch (error) {
|
||||||
|
// debugText.value = `Error: ${JSON.stringify(error, null, 2)}`;
|
||||||
|
// console.error(error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
const updateProject = async () => {
|
||||||
|
try {
|
||||||
|
const headers = { 'Authorization': `Bearer ${token.value}` };
|
||||||
|
const data = {
|
||||||
|
title: projectData.value.title,
|
||||||
|
description: projectData.value.description,
|
||||||
|
demo_link: projectData.value.demo_link,
|
||||||
|
source_link: projectData.value.source_link,
|
||||||
|
tags: projectData.value.tags,
|
||||||
|
|
||||||
|
};
|
||||||
|
const response = await axios.patch(`http://somebodyhire.me/api/projects/${projectId.value}/`, data, { headers });
|
||||||
|
router.push(`/project/${response.data.id}`);
|
||||||
|
} catch (error) {
|
||||||
|
debugText.value = `Error: ${JSON.stringify(error, null, 2)}`;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelUpdate = () => {
|
||||||
|
router.push('/myprojects');
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async() => {
|
||||||
|
projectId.value = route.params.id;
|
||||||
|
await getProject();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NavbarDefault />
|
||||||
|
<div class="profile-container">
|
||||||
|
<H1> Страница Редактирования Проекта {{ projectId }}</H1>
|
||||||
|
<div v-if="!isAuthenticated">
|
||||||
|
<h1>Вы не авторизованы</h1>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div v-if = "userId == projectData.owner">
|
||||||
|
<h1>User Profile: {{ loggedUserName }}</h1>
|
||||||
|
<textarea readonly v-model="debugText"></textarea>
|
||||||
|
<input type="text" v-model="projectData.title" placeholder="Title">
|
||||||
|
<input type="text" v-model="projectData.description" placeholder="Description">
|
||||||
|
<textarea v-model="projectData.demo_link" placeholder="Demo link"></textarea>
|
||||||
|
<textarea v-model="projectData.source_link" placeholder="Source code link"></textarea>
|
||||||
|
<textarea v-model="projectData.tags" placeholder="Tags"></textarea>
|
||||||
|
<button @click="updateProject" class="btn-submit">Update</button>
|
||||||
|
<button @click="cancelUpdate" class="btn-cancel">Cancel</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<h1>Вы не являетесь владельцем проекта</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.profile-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 80%;
|
||||||
|
margin: auto;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-container img {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.profile-container input, .profile-container textarea {
|
||||||
|
width: 100%; /* Make inputs and textareas take up the full width of the container */
|
||||||
|
padding: 10px; /* Add some padding */
|
||||||
|
margin-bottom: 15px; /* Add some margin */
|
||||||
|
box-sizing: border-box; /* Ensure padding doesn't affect final dimensions */
|
||||||
|
border: 1px solid #ccc; /* Add a border */
|
||||||
|
border-radius: 5px; /* Add rounded corners */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style for smaller screens */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.profile-container {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.btn-submit {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #4CAF50;
|
||||||
|
border: none;
|
||||||
|
padding: 15px 32px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 4px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #f44336;
|
||||||
|
border: none;
|
||||||
|
padding: 15px 32px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 4px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
102
src/views/LandingPages/Project/MyProjects.vue
Normal file
102
src/views/LandingPages/Project/MyProjects.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, onUnmounted, computed } from "vue";
|
||||||
|
import axios from 'axios';
|
||||||
|
import { ref } from "vue";
|
||||||
|
import NavbarDefault from "../../../examples/navbars/NavbarDefault.vue";
|
||||||
|
|
||||||
|
const searchQuery = ref('');
|
||||||
|
const searchResultProjects = ref([]);
|
||||||
|
const searchResultUsers = ref([]);
|
||||||
|
|
||||||
|
const userId = computed(() => sessionStorage.getItem('user_id'));
|
||||||
|
const username = computed(() => sessionStorage.getItem('username'));
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
try {
|
||||||
|
const projectsResponse = await axios.get(`http://somebodyhire.me/api/search/projects/?search_query=${searchQuery.value}`);
|
||||||
|
searchResultProjects.value = projectsResponse.data;
|
||||||
|
|
||||||
|
const usersResponse = await axios.get(`http://somebodyhire.me/api/search/profiles/?search_query=${searchQuery.value}`);
|
||||||
|
searchResultUsers.value = usersResponse.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('There was an error fetching the search results', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
search();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NavbarDefault />
|
||||||
|
<div>
|
||||||
|
<h2 class="result-header">Проекты пользователя {{ username }}</h2>
|
||||||
|
<div class="result-grid">
|
||||||
|
<div class="result-card" v-for="project in searchResultProjects" :key="project.id">
|
||||||
|
<div v-if = "project.owner == userId" class="project-owner-note">
|
||||||
|
<h3>{{ project.title }} with ID {{ project.id }}</h3>
|
||||||
|
<p>{{ project.description }}</p>
|
||||||
|
<p>Создатель: {{ project.owner }} </p>
|
||||||
|
<a :href="`/project/${project.id}`">Страница проекта</a>
|
||||||
|
<p></p>
|
||||||
|
<a :href="`/editproject/${project.id}`">Редактирование проекта</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.searchBar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.result-header {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #333;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: rgba(92, 90, 90, 0.5);
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: calc(100% / 3 - 20px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 992px) {
|
||||||
|
.result-card {
|
||||||
|
width: calc(100% / 2 - 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.result-card {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -1,13 +1,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref, computed } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import NavbarDefault from '../../../examples/navbars/NavbarDefault.vue';
|
||||||
|
|
||||||
|
|
||||||
const projectId = ref(null);
|
const projectId = ref(null);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const projectData = ref([]);
|
const projectData = ref([]);
|
||||||
|
|
||||||
|
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token'));
|
||||||
|
const userId = computed(() => sessionStorage.getItem('user_id'));
|
||||||
|
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
||||||
|
const token = computed(() => sessionStorage.getItem('access_token'));
|
||||||
|
|
||||||
onMounted(async() => {
|
onMounted(async() => {
|
||||||
projectId.value = route.params.id;
|
projectId.value = route.params.id;
|
||||||
await getProject();
|
await getProject();
|
||||||
@ -30,27 +36,89 @@ const getProject = async () => {
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="projectData">
|
<NavbarDefault />
|
||||||
<h1>Проект номер: {{ projectData.id }}</h1>
|
<div v-if="projectData" class="project-container">
|
||||||
<h2>{{ projectData.title }}</h2>
|
<h1 class="project-title">Проект номер: {{ projectData.id }}</h1>
|
||||||
<p>{{ projectData.description }}</p>
|
<h2 class="project-subtitle">{{ projectData.title }}</h2>
|
||||||
<img :src="projectData.featured_image" alt="Featured image">
|
<div v-if = "projectData.owner == userId" class="project-owner-note">
|
||||||
<p v-if="projectData.demo_link">Demo Link: <a :href="projectData.demo_link">{{ projectData.demo_link }}</a></p>
|
<a :href="`/editproject/${projectData.id}`">Редактирование проекта</a>
|
||||||
<p v-if="projectData.source_link">Source Link: <a :href="projectData.source_link">{{ projectData.source_link }}</a></p>
|
</div>
|
||||||
<p>Total Votes: {{ projectData.vote_total }}</p>
|
<p class="project-description">{{ projectData.description }}</p>
|
||||||
<p>Vote Ratio: {{ projectData.vote_ratio }}</p>
|
<img class="project-image" :src="projectData.featured_image" alt="Featured image">
|
||||||
<p>Created On: {{ new Date(projectData.created).toLocaleDateString() }}</p>
|
<p v-if="projectData.demo_link" class="project-demo-link">Demo Link: <a :href="projectData.demo_link">{{ projectData.demo_link }}</a></p>
|
||||||
<p>Owner ID: {{ projectData.owner }}</p>
|
<p v-if="projectData.source_link" class="project-source-link">Source Link: <a :href="projectData.source_link">{{ projectData.source_link }}</a></p>
|
||||||
<p>Tags:
|
<p class="project-votes">Total Votes: {{ projectData.vote_total }}</p>
|
||||||
<span v-for="(tag, index) in projectData.tags" :key="index">
|
<p class="project-vote-ratio">Vote Ratio: {{ projectData.vote_ratio }}</p>
|
||||||
|
<p class="project-created">Created On: {{ new Date(projectData.created).toLocaleDateString() }}</p>
|
||||||
|
<p class="project-owner-id">Owner ID: {{ projectData.owner }}</p>
|
||||||
|
<p class="project-tags">Tags:
|
||||||
|
<span v-for="(tag, index) in projectData.tags" :key="index" class="project-tag">
|
||||||
{{ tag }}<span v-if="index < projectData.tags.length - 1">, </span>
|
{{ tag }}<span v-if="index < projectData.tags.length - 1">, </span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.project-container {
|
||||||
|
margin: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-subtitle {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-owner-note {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #777;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-description {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-demo-link, .project-source-link {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #337ab7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-votes, .project-vote-ratio, .project-created, .project-owner-id {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-tags {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-tag {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -15,9 +15,12 @@ const username = ref('');
|
|||||||
const password = ref('');
|
const password = ref('');
|
||||||
const errorMessage = ref('');
|
const errorMessage = ref('');
|
||||||
|
|
||||||
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token')); // Computed property to check if the user is authenticated
|
//Это блок для работы с хранилищем сессии
|
||||||
|
const isAuthenticated = computed(() => !!sessionStorage.getItem('access_token'));
|
||||||
const userId = computed(() => sessionStorage.getItem('user_id'));
|
const userId = computed(() => sessionStorage.getItem('user_id'));
|
||||||
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
const loggedUserName = computed(() => sessionStorage.getItem('username'));
|
||||||
|
const isStaff = computed(() => sessionStorage.getItem('is_staff'));
|
||||||
|
const token = computed(() => sessionStorage.getItem('token'));
|
||||||
|
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
if (!username.value || !password.value) {
|
if (!username.value || !password.value) {
|
||||||
@ -34,10 +37,11 @@ const login = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(url, body, { headers });
|
const response = await axios.post(url, body, { headers });
|
||||||
// Removed debug information from output
|
|
||||||
sessionStorage.setItem('access_token', response.data.access);
|
sessionStorage.setItem('access_token', response.data.access);
|
||||||
sessionStorage.setItem('username', username.value); // Save username in sessionStorage
|
sessionStorage.setItem('username', username.value);
|
||||||
sessionStorage.setItem('user_id', response.data.id); // Save the user id in sessionStorage
|
sessionStorage.setItem('user_id', response.data.id);
|
||||||
|
sessionStorage.setItem('is_staff', response.data.is_staff);
|
||||||
|
sessionStorage.setItem('token', response.data.token);
|
||||||
location.reload(); // Refresh page
|
location.reload(); // Refresh page
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
@ -55,6 +59,8 @@ const logout = () => {
|
|||||||
sessionStorage.removeItem('access_token');
|
sessionStorage.removeItem('access_token');
|
||||||
sessionStorage.removeItem('username'); // Also clear the username from sessionStorage
|
sessionStorage.removeItem('username'); // Also clear the username from sessionStorage
|
||||||
sessionStorage.removeItem('user_id');
|
sessionStorage.removeItem('user_id');
|
||||||
|
sessionStorage.setItem('is_staff', false);
|
||||||
|
sessionStorage.removeItem('token');
|
||||||
location.reload(); // Refresh page after logout
|
location.reload(); // Refresh page after logout
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,7 +126,16 @@ export default {
|
|||||||
<div>
|
<div>
|
||||||
<div v-if="isAuthenticated">
|
<div v-if="isAuthenticated">
|
||||||
<!-- This will only be displayed if the user is authenticated -->
|
<!-- This will only be displayed if the user is authenticated -->
|
||||||
<p>Вы вошли в аккаунт {{ loggedUserName }}, ваш ID {{ userId }}</p>
|
<p>Вы вошли в аккаунт {{ loggedUserName }}</p>
|
||||||
|
<p>
|
||||||
|
<a href="/ViewMyProfile">Перейти в профиль.</a>
|
||||||
|
</p>
|
||||||
|
<!-- Это должно быть видно только админам -->
|
||||||
|
<div v-if="isStaff">
|
||||||
|
<p>
|
||||||
|
<a href="/admin">Перейти в панель администратора.</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<button @click="logout">Выход</button>
|
<button @click="logout">Выход</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -128,9 +143,6 @@ export default {
|
|||||||
<!-- This will be displayed if the user is not authenticated -->
|
<!-- This will be displayed if the user is not authenticated -->
|
||||||
<p>Пожалуйста, введите логин и пароль</p>
|
<p>Пожалуйста, введите логин и пароль</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input v-model="username" type="text" placeholder="Имя пользователя" />
|
<input v-model="username" type="text" placeholder="Имя пользователя" />
|
||||||
</div>
|
</div>
|
||||||
@ -151,16 +163,7 @@ export default {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<p class="mt-4 text-sm text-center">
|
||||||
|
|
||||||
|
|
||||||
<div v-if="errorMessage">
|
|
||||||
<p>{{ errorMessage }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p class="mt-4 text-sm text-center">
|
|
||||||
Нет аккаунта?
|
Нет аккаунта?
|
||||||
<a
|
<a
|
||||||
href="/register"
|
href="/register"
|
||||||
@ -170,12 +173,24 @@ export default {
|
|||||||
</p>
|
</p>
|
||||||
<p class="mt-4 text-sm text-center">
|
<p class="mt-4 text-sm text-center">
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="/forgot"
|
href="/forgot"
|
||||||
class="text-success text-gradient font-weight-bold"
|
class="text-success text-gradient font-weight-bold"
|
||||||
>Забыли пароль</a
|
>Забыли пароль</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="errorMessage">
|
||||||
|
<p>{{ errorMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,18 +1,3 @@
|
|||||||
<style scoped>
|
|
||||||
.project-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.project-card {
|
|
||||||
flex-basis: calc(33.33% - 1em); /* 1em is for margin */
|
|
||||||
margin: 0.5em;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
padding: 1em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUnmounted, computed, } from "vue";
|
import { onMounted, onUnmounted, computed, } from "vue";
|
||||||
|
|
||||||
@ -87,35 +72,29 @@ export default {
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-7 text-center mx-auto position-relative">
|
<div class="col-lg-7 text-center mx-auto position-relative">
|
||||||
<h1
|
|
||||||
class="text-white pt-3 mt-n5 me-2"
|
|
||||||
:style="{ display: 'inline-block ', fontFamily: 'PressStart2P, sans-serif' }"
|
|
||||||
>
|
|
||||||
LinkedMin
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</p>
|
|
||||||
<div v-if="isAuthenticated">
|
<div v-if="isAuthenticated">
|
||||||
<h2
|
<h2
|
||||||
class="text-white pt-3 mt-n5 me-2"
|
class="text-white pt-3 mt-n5 me-2"
|
||||||
:style="{ display: 'inline-block ', fontFamily: 'PressStart2P, sans-serif' }"
|
:style="{ display: 'inline-block ', fontFamily: 'PressStart2P, sans-serif' }"
|
||||||
>
|
>
|
||||||
Привет, {{ loggedUserName }}</h2>
|
Привет, {{ loggedUserName }}!</h2>
|
||||||
|
<p class="lead text-white px-5 mt-3" :style="{ fontWeight: '500', fontFamily: 'PressStart2P, sans-serif' }">
|
||||||
|
В поисках чего-то интересного?
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<p>Тариф Бесплатный</p>
|
<h1
|
||||||
|
class="text-white pt-3 mt-n5 me-2"
|
||||||
|
:style="{ display: 'inline-block ', fontFamily: 'PressStart2P, sans-serif' }">LinkedMin</h1>
|
||||||
|
<p class="lead text-white px-5 mt-3" :style="{ fontWeight: '500', fontFamily: 'PressStart2P, sans-serif' }">
|
||||||
|
Показывай себя и свои проекты.
|
||||||
|
Находи вдохновение, коллег и новые знания.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="lead text-white px-5 mt-3" :style="{ fontWeight: '500', fontFamily: 'PressStart2P, sans-serif' }">
|
|
||||||
Показывай себя и свои проекты.
|
|
||||||
Находи вдохновение, коллег и новые знания.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -130,4 +109,17 @@ export default {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.project-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.project-card {
|
||||||
|
flex-basis: calc(33.33% - 1em); /* 1em is for margin */
|
||||||
|
margin: 0.5em;
|
||||||
|
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
||||||
|
padding: 1em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
@ -33,11 +33,11 @@ const search = async () => {
|
|||||||
<!-- Added class searchInput for styling -->
|
<!-- Added class searchInput for styling -->
|
||||||
<input class="searchInput" type="text" v-model="searchQuery" @keyup.enter="search" placeholder="Поиск по проектам и людям" />
|
<input class="searchInput" type="text" v-model="searchQuery" @keyup.enter="search" placeholder="Поиск по проектам и людям" />
|
||||||
<!-- Added class searchButton for styling -->
|
<!-- Added class searchButton for styling -->
|
||||||
<button class="searchButton" type="submit" @click="search">Go</button>
|
<button class="searchButton" type="submit" @click="search">Погнали!</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="searchResultProjects.length > 0 || searchResultUsers.length > 0">
|
<div v-if="searchResultProjects.length > 0 || searchResultUsers.length > 0">
|
||||||
<h2 class="result-header">Найдено проектов: {{ searchResultProjects.length}} </h2>
|
<!--<h2 class="result-header">Найдено проектов: {{ searchResultProjects.length}} </h2>-->
|
||||||
<div class="result-grid">
|
<div class="result-grid">
|
||||||
<div class="result-card" v-for="project in searchResultProjects" :key="project.id">
|
<div class="result-card" v-for="project in searchResultProjects" :key="project.id">
|
||||||
<h3>{{ project.title }} with ID {{ project.id }}</h3>
|
<h3>{{ project.title }} with ID {{ project.id }}</h3>
|
||||||
@ -45,7 +45,7 @@ const search = async () => {
|
|||||||
<a :href="`http://somebodyhire.me/project/${project.id}`">Страница проекта</a>
|
<a :href="`http://somebodyhire.me/project/${project.id}`">Страница проекта</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="result-header">Найдено людей: {{ searchResultUsers.length}} </h2>
|
<!--<h2 class="result-header">Найдено людей: {{ searchResultUsers.length}} </h2>-->
|
||||||
<div class="result-grid">
|
<div class="result-grid">
|
||||||
<div class="result-card" v-for="user in searchResultUsers" :key="user.id">
|
<div class="result-card" v-for="user in searchResultUsers" :key="user.id">
|
||||||
<h3>{{ user.username }} with id {{ user.id }}</h3>
|
<h3>{{ user.username }} with id {{ user.id }}</h3>
|
||||||
@ -56,7 +56,7 @@ const search = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div v-if = "searchQuery.length > 0 && searchButtonIsPressed === true" >
|
<div v-if = "searchQuery.length > 0 && searchButtonIsPressed === true" >
|
||||||
<h2 class="result-header">Ничего не найдено</h2>
|
<h2 class="result-header">Увы и ах! Такого нет (</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -78,30 +78,42 @@ const search = async () => {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
/* Adds some margin to the right side of the input field */
|
/* Adds some margin to the right side of the input field */
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
/* Increased the font size a bit */
|
/* Increased the font size a bit */
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
border-radius: 1%;
|
||||||
|
|
||||||
|
border: 2px solid #66FCF1;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
background: #FAFAFA;
|
||||||
|
color: #9E9C9C;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchButton {
|
.searchButton {
|
||||||
/* Adds some padding inside the button */
|
/* Adds some padding inside the button */
|
||||||
padding: 10px 20px;
|
padding: 12px 20px;
|
||||||
/* Changes the font size */
|
/* Changes the font size */
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
/* Changes the background color of the button */
|
/* Changes the background color of the button */
|
||||||
background-color: #3d9132;
|
background-color: #66FCF1;
|
||||||
/* Changes the color of the text inside the button */
|
/* Changes the color of the text inside the button */
|
||||||
color: white;
|
color: rgb(90, 90, 90);
|
||||||
/* Makes the border corners rounded */
|
/* Makes the border corners rounded */
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
/* Removes the default button border */
|
/* Removes the default button border */
|
||||||
border: none;
|
border: none;
|
||||||
/* Changes the cursor to a hand pointer when hovering over the button */
|
/* Changes the cursor to a hand pointer when hovering over the button */
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
width: 10%;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchButton:hover {
|
.searchButton:hover {
|
||||||
/* Changes the background color of the button when hovering over it */
|
/* Changes the background color of the button when hovering over it */
|
||||||
background-color: #25581e;
|
background-color: #E01EB2;
|
||||||
|
color: rgb(228, 228, 228);
|
||||||
}
|
}
|
||||||
.result-header {
|
.result-header {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -109,6 +121,11 @@ const search = async () => {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
|
border: 2px solid #66FCF1;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
color: #9E9C9C;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-grid {
|
.result-grid {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user