BambitTestTask/pages/index.vue
2025-11-18 17:43:35 +03:00

164 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="index-page">
<div class="index-page__search">
<UInput
:model-value="search"
size="xl"
class="w-full"
placeholder="Поиск..."
:loading="postsIsLoading || usersIsLoading"
@update:model-value="updateSearch"
/>
</div>
<UiTable :table-data="tableData" :columns="columns" />
<UModal v-model:open="open" :title="selectedUser?.email">
<template #body>
<div>
<div>Имя: {{ selectedUser?.name }}</div>
<div>Логин: {{ selectedUser?.username }}</div>
<div>Электронная почта: {{ selectedUser?.email }}</div>
<div>Телефон: {{ selectedUser?.phone }}</div>
<a :href="`https://${selectedUser?.website}`" target="_blank">Веб-сайт: <span class="title-cell">{{ selectedUser?.website }}</span></a>
<div>Название компании: {{ selectedUser?.company?.name }}</div>
<div>Адрес: {{ `${selectedUser?.address?.street} ${selectedUser?.address?.suite} ${selectedUser?.address?.city}` }}</div>
</div>
</template>
</UModal>
</div>
</template>
<script setup lang="ts">
import { UTooltip } from '#components'
import {
createColumnHelper,
} from '@tanstack/vue-table'
import { useDebounceFn, useMediaQuery } from '@vueuse/core'
import { useGetPosts, useGetUsers } from '~/api/queries'
import UiTable from '~/components/UiTable.vue'
const isMobile = useMediaQuery('(max-width: 1280px)')
const open = ref(false)
const selectedUser = ref<User | null>(null)
const search = ref('')
const updateSearch = useDebounceFn((value: string) => {
search.value = value
}, 500)
const { data: posts, isLoading: postsIsLoading } = useGetPosts(search)
const { data: users, isLoading: usersIsLoading } = useGetUsers()
const tableData = computed(() => (posts?.value ?? []).map(post => ({
userId: post?.userId,
userEmail: users?.value?.find(user => user?.id === post?.userId)?.email,
id: post?.id,
title: post?.title,
body: post?.body,
})))
const columnHelper = createColumnHelper<Posts>()
const columns = [
columnHelper.accessor('id', {
header: 'ID',
footer: props => props?.column?.id,
meta: {
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
},
size: 50,
}),
columnHelper.accessor('title', {
header: 'Заголовок',
cell: info => isMobile.value
? info.getValue()
: h(UTooltip, { text: info.getValue(),
}, {
default: () => h('span', { class: 'ellipsis' }, truncate(info.getValue()),
),
}),
size: 150,
}),
columnHelper.accessor('userEmail', {
header: 'Автор',
cell: info => isMobile.value
? info.getValue()
: h(UTooltip, { text: info.getValue(),
}, {
default: () => h('div', { class: 'title-cell', onClick: () => openPost(info?.row?.original) }, truncate(info.getValue()),
),
}),
meta: {
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
},
size: 170,
}),
columnHelper.accessor('body', {
header: 'Контент',
cell: info => isMobile.value
? info.getValue()
: h(UTooltip, {
text: info.getValue(),
}, {
default: () => h('span', { class: 'ellipsis' }, truncate(info.getValue(), 22)),
}),
size: 220,
}),
]
function openPost(post: Post) {
selectedUser.value = users?.value?.find(user => user?.id === post?.userId)
open.value = true
}
function truncate(text: string, max = 15) {
return text?.length > max ? `${text?.slice(0, max)}` : text
}
</script>
<style lang="scss">
.index-page {
display: flex;
flex-direction: column;
gap: 20px;
max-width: 600px;
margin-inline: auto;
padding-bottom: 40px;
position: relative;
&__search {
position: fixed;
top: 48px;
left: 50%;
transform: translateX(-50%);
max-width: 600px;
width: 100%;
z-index: 1000;
background: var(--ui-bg-base);
@include mobile {
padding-inline: 10px;
}
}
}
/* -------------------- CLICKABLE USER EMAIL CELL -------------------- */
.title-cell {
cursor: pointer;
text-decoration: underline;
color: var(--ui-primary);
}
.title-cell:hover {
color: var(--ui-primary-hover);
}
</style>