Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/atrium-telegram/app/components/StaffBlock.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="max-w-full overflow-x-scroll overflow-y-hidden snap-x hide-scroll">
<div class="w-max flex flex-row flex-wrap gap-2">
<div class="max-w-full overflow-x-auto overflow-y-hidden snap-x hide-scroll relative">
<div class="flex flex-row gap-3">
<div
v-for="user in allUsers"
:key="user.id"
Expand All @@ -10,7 +10,7 @@
<div class="relative">
<UAvatar
:src="user?.avatarUrl ?? undefined"
class="size-16 border-2 border-default"
class="size-16 border-3 border-default"
:class="[
user.isOnline && 'border-primary',
]"
Expand Down
39 changes: 25 additions & 14 deletions apps/atrium-telegram/app/components/TaskInfoCard.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
<template>
<ActiveCard class="motion-preset-slide-left">
<ActiveCard>
<Section>
<div class="flex flex-row gap-2 items-center">
<UAvatar :src="performer?.avatarUrl ?? undefined" class="size-8" />

<div v-if="isCompleted" class="flex flex-row gap-1 items-center text-primary">
<UIcon
name="i-lucide-check"
class="shrink-0 size-8 text-primary"
/>
<p v-if="task.completedAt" class="text-base/5 font-semibold">
{{ format(new Date(task.completedAt), 'd MMMM yyyy в HH:mm', { locale: ru }) }}
</p>
</div>
<UIcon
:name="isCompleted ? 'i-lucide-check' : 'i-lucide-loader-circle'"
class="shrink-0 size-8"
:class="[
isCompleted ? 'text-primary' : 'text-muted/50',
!isCompleted && 'motion-preset-spin motion-duration-4000',
]"
v-else
name="i-lucide-loader-circle"
class="shrink-0 size-8 text-muted/50 motion-preset-spin motion-duration-4000"
/>

<div v-if="isFocused" class="flex flex-row items-center gap-1.5 text-primary">
<UIcon
name="i-lucide-goal"
class="shrink-0 size-8 motion-preset-seesaw"
/>
<p class="max-w-22 text-sm/4 font-bold">
В Фокусе
</p>
</div>
</div>

<h3 class="text-xl/6 font-bold">
Expand All @@ -28,13 +44,6 @@
{{ task.report }}
</p>
</div>

<div v-if="task?.completedAt" class="flex flex-row gap-2 items-start w-full">
<UIcon name="i-lucide-calendar" class="shrink-0 size-5 text-primary" />
<p class="text-base/5 font-semibold">
{{ format(new Date(task.completedAt), 'd MMMM yyyy в HH:mm', { locale: ru }) }}
</p>
</div>
</Section>
</ActiveCard>
</template>
Expand All @@ -52,4 +61,6 @@ const userStore = useUserStore()

const isCompleted = computed(() => !!task.completedAt)
const performer = computed(() => userStore.staff.find((staff) => staff.id === task.performerId))

const isFocused = computed(() => task.id === performer.value?.focusedTaskId)
</script>
4 changes: 2 additions & 2 deletions apps/atrium-telegram/app/composables/useNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ function _useNavigation() {
badge: flowStore.nowViewedItemsCount > 10 ? '10+' : flowStore.nowViewedItemsCount.toString(),
},
{
path: '/tasks',
names: ['tasks'],
path: '/task/my',
names: ['my-tasks'],
title: t('app.my-tasks'),
icon: 'i-lucide-layout-dashboard',
badge: taskStore.myTodayTasks.length.toString(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<PageContainer>
<Section>
<Section class="motion-preset-slide-left">
<div class="flex flex-row gap-2 items-center">
<UIcon
name="i-lucide-scroll"
Expand Down
2 changes: 1 addition & 1 deletion apps/atrium-telegram/app/pages/flow/[itemId]/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<PageContainer>
<Section>
<Section class="motion-preset-slide-left">
<div class="flex flex-row items-start justify-between gap-2.5">
<UAvatar
v-if="item?.userId"
Expand Down
4 changes: 2 additions & 2 deletions apps/atrium-telegram/app/pages/navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ const items = ref([
},
{
label: 'Задачи',
to: '/all-tasks',
icon: 'i-lucide-list-checks',
to: '/task/all',
icon: 'i-lucide-list-todo',
badge: 'апдейт',
onClick: () => vibrate(),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<PageContainer>
<Section>
<Section class="motion-preset-slide-left">
<div class="flex flex-row gap-2 items-center">
<UIcon
name="i-lucide-user"
Expand Down
109 changes: 109 additions & 0 deletions apps/atrium-telegram/app/pages/task/[taskId]/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<template>
<PageContainer>
<Section class="motion-preset-slide-left">
<div class="flex flex-row gap-2 items-center">
<UAvatar :src="performer?.avatarUrl ?? undefined" class="size-8" />

<div v-if="isCompleted" class="flex flex-row gap-1 items-center text-primary">
<UIcon
name="i-lucide-check"
class="shrink-0 size-8 text-primary"
/>
<p v-if="task?.completedAt" class="text-base/5 font-semibold">
{{ format(new Date(task.completedAt), 'd MMMM yyyy в HH:mm', { locale: ru }) }}
</p>
</div>
<UIcon
v-else
name="i-lucide-loader-circle"
class="shrink-0 size-8 text-muted/50 motion-preset-spin motion-duration-4000"
/>

<div v-if="isFocused" class="flex flex-row items-center gap-1.5 text-primary">
<UIcon
name="i-lucide-goal"
class="shrink-0 size-8 motion-preset-seesaw"
/>
<p class="max-w-22 text-sm/4 font-bold">
В Фокусе
</p>
</div>
Comment on lines +7 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Significant code duplication with TaskInfoCard.vue.

The completed state UI (lines 7-15) and focused state UI (lines 22-30) are duplicated verbatim from TaskInfoCard.vue. This duplication extends to the date formatting logic and icon configuration.

Consider extracting these state indicator blocks into a reusable component (e.g., TaskStatusIndicators.vue) that both the card and detail page can use.

Example refactor:

<!-- TaskStatusIndicators.vue -->
<template>
  <div class="flex flex-row gap-2 items-center">
    <UAvatar :src="performer?.avatarUrl ?? undefined" class="size-8" />

    <div v-if="isCompleted" class="flex flex-row gap-1 items-center text-primary">
      <UIcon name="i-lucide-check" class="shrink-0 size-8 text-primary" />
      <p v-if="completedAt" class="text-base/5 font-semibold">
        {{ format(new Date(completedAt), 'd MMMM yyyy в HH:mm', { locale: ru }) }}
      </p>
    </div>
    <UIcon
      v-else
      name="i-lucide-loader-circle"
      class="shrink-0 size-8 text-muted/50 motion-preset-spin motion-duration-4000"
    />

    <div v-if="isFocused" class="flex flex-row items-center gap-1.5 text-primary">
      <UIcon name="i-lucide-goal" class="shrink-0 size-8 motion-preset-seesaw" />
      <p class="max-w-22 text-sm/4 font-bold">В Фокусе</p>
    </div>
  </div>
</template>

Then use it in both files:

<TaskStatusIndicators 
  :performer="performer"
  :is-completed="isCompleted"
  :completed-at="task?.completedAt"
  :is-focused="isFocused"
/>

</div>

<SectionTitle :title="task?.name ?? ''" />

<div v-if="task?.description" class="w-full text-base/5 font-normal whitespace-pre-wrap break-words">
{{ task.description }}
</div>

<div v-if="task?.report" class="flex flex-row gap-2 items-start w-full">
<UIcon name="i-lucide-clipboard-pen" class="shrink-0 size-6 text-primary" />
<p class="text-base/5 font-semibold whitespace-pre-wrap break-words">
{{ task.report }}
</p>
</div>

<div v-if="task?.date" class="flex flex-row gap-2 items-start w-full">
<UIcon name="i-lucide-calendar" class="shrink-0 size-6 text-primary" />
<p class="text-base/5 font-semibold whitespace-pre-wrap break-words">
{{ format(new Date(task.date), 'd MMMM yyyy', { locale: ru }) }}
</p>
</div>

<div v-if="taskList" class="flex flex-row gap-2 items-start w-full">
<UIcon name="i-lucide-book-marked" class="shrink-0 size-6 text-primary" />
<p class="text-base/5 font-semibold whitespace-pre-wrap break-words">
{{ taskList.name }}
</p>
</div>

<div class="mt-6 flex flex-col gap-0.5">
<div class="text-sm text-muted">
Создана
<time
v-if="task?.createdAt"
:datetime="task.createdAt"
v-text="format(new Date(task.createdAt), 'd MMMM yyyy в HH:mm', { locale: ru })"
/>
</div>

<div v-if="task?.updatedAt" class="text-sm text-muted">
Обновлена
<time
:datetime="task.updatedAt"
v-text="format(new Date(task.updatedAt), 'd MMMM yyyy в HH:mm', { locale: ru })"
/>
</div>

<div v-if="task?.completedAt" class="text-sm text-muted">
Закрыта
<time
:datetime="task.completedAt"
v-text="format(new Date(task.completedAt), 'd MMMM yyyy в HH:mm', { locale: ru })"
/>
</div>
</div>
</Section>
</PageContainer>
</template>

<script setup lang="ts">
import { format } from 'date-fns'
import { ru } from 'date-fns/locale/ru'

definePageMeta({
name: 'task-taskId',
})

const { params } = useRoute('task-taskId')

const userStore = useUserStore()
const taskStore = useTaskStore()
const task = computed(() => taskStore.tasks.find((t) => t.id === params.taskId))
const taskList = computed(() => taskStore.lists.find((t) => t.id === task.value?.listId))

const isCompleted = computed(() => !!task.value?.completedAt)
const performer = computed(() => userStore.staff.find((staff) => staff.id === task.value?.performerId))

const isFocused = computed(() => task.value?.id === performer.value?.focusedTaskId)
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,14 @@

<div class="flex flex-col gap-2.5">
<div class="flex flex-col gap-4">
<TaskInfoCard
<NuxtLink
v-for="task in filteredTasks.show"
:key="task.id"
:task="task"
/>
:to="`/task/${task.id}`"
class="motion-preset-slide-left"
>
<TaskInfoCard :task="task" />
</NuxtLink>

<UButton
v-if="filteredTasks.canShowMore"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
<script setup lang="ts">
import { ModalCreateTaskList, ModalUploadUserAvatar } from '#components'

definePageMeta({
name: 'my-tasks',
})

const { vibrate } = useFeedback()

const overlay = useOverlay()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<PageContainer>
<Section>
<Section class="motion-preset-slide-left">
<div class="flex flex-row items-start justify-between gap-2.5">
<UIcon name="i-lucide-mail-question-mark" class="size-10 text-primary" />

Expand Down