diff --git a/apps/atrium-telegram/app/app.vue b/apps/atrium-telegram/app/app.vue
index 2209e0b3..907f0ce6 100644
--- a/apps/atrium-telegram/app/app.vue
+++ b/apps/atrium-telegram/app/app.vue
@@ -60,7 +60,7 @@ watch(colorMode, () => {
// Init Stores
const user = useUserStore()
const task = useTaskStore()
-const epic = useEpicStore()
+const ticket = useTicketStore()
const kitchen = useKitchenStore()
const flow = useFlowStore()
@@ -79,7 +79,7 @@ onMounted(async () => {
user.updateOnline(),
user.update(),
task.update(),
- epic.update(),
+ ticket.update(),
kitchen.update(),
flow.update(),
])
@@ -89,11 +89,11 @@ onMounted(async () => {
user.updateOnline(),
user.update(),
task.update(),
- epic.update(),
+ ticket.update(),
kitchen.update(),
flow.update(),
])
- }, 30000)
+ }, 20000)
})
onUnmounted(() => {
diff --git a/apps/atrium-telegram/app/components/TicketCard.vue b/apps/atrium-telegram/app/components/TicketCard.vue
new file mode 100644
index 00000000..beeac332
--- /dev/null
+++ b/apps/atrium-telegram/app/components/TicketCard.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+ {{ ticket.title }}
+
+
+
+ {{ ticket.description }}
+
+
+
+
+
+
+
{{ ticket?.messages.length }}
+
+
+
+
+
+
+
+
+
diff --git a/apps/atrium-telegram/app/components/TicketMessage.vue b/apps/atrium-telegram/app/components/TicketMessage.vue
new file mode 100644
index 00000000..a5da2611
--- /dev/null
+++ b/apps/atrium-telegram/app/components/TicketMessage.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ message?.text }}
+
+
+
+
+ Прикрепленный файл
+
+
+
+
![]()
+
+
+
+ {{ format(new Date(message.createdAt), 'dd MMMM в HH:mm', { locale: ru }) }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/atrium-telegram/app/composables/useNavigation.ts b/apps/atrium-telegram/app/composables/useNavigation.ts
index cb9b8deb..793314b0 100644
--- a/apps/atrium-telegram/app/composables/useNavigation.ts
+++ b/apps/atrium-telegram/app/composables/useNavigation.ts
@@ -16,10 +16,10 @@ function _useNavigation() {
badge: flowStore.nowViewedItemsCount.toString(),
},
{
- path: '/epic',
- names: ['epic', 'epic-epicId'],
- title: t('app.epics'),
- icon: 'i-lucide-crown',
+ path: '/ticket',
+ names: ['ticket', 'ticket-ticketId'],
+ title: t('app.tickets'),
+ icon: 'i-lucide-mail-question-mark',
},
{
path: '/tasks',
diff --git a/apps/atrium-telegram/app/pages/index.vue b/apps/atrium-telegram/app/pages/index.vue
index 6e5e115a..d2eca897 100644
--- a/apps/atrium-telegram/app/pages/index.vue
+++ b/apps/atrium-telegram/app/pages/index.vue
@@ -34,6 +34,10 @@
+
+
+
+
diff --git a/apps/atrium-telegram/app/pages/startapp.vue b/apps/atrium-telegram/app/pages/startapp.vue
index ed7a950f..a9bd5623 100644
--- a/apps/atrium-telegram/app/pages/startapp.vue
+++ b/apps/atrium-telegram/app/pages/startapp.vue
@@ -27,6 +27,9 @@ if (tgWebAppStartParam?.length && tgWebAppStartParam.includes(separator)) {
case 'epic':
await navigateTo({ path: `/epic/${value}`, query })
break
+ case 'ticket':
+ await navigateTo({ path: `/ticket/${value}`, query })
+ break
default:
await navigateTo('/')
}
diff --git a/apps/atrium-telegram/app/pages/ticket/[ticketId]/index.vue b/apps/atrium-telegram/app/pages/ticket/[ticketId]/index.vue
new file mode 100644
index 00000000..b548881e
--- /dev/null
+++ b/apps/atrium-telegram/app/pages/ticket/[ticketId]/index.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+ {{ ticket?.title }}
+
+
+
+ {{ ticket?.description }}
+
+
+
+
+
+
+ {{ ticket?.messages.length }} {{ pluralizationRu(ticket?.messages.length ?? 0, ['сообщение', 'сообщения', 'сообщений']) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/atrium-telegram/app/pages/ticket/index.vue b/apps/atrium-telegram/app/pages/ticket/index.vue
new file mode 100644
index 00000000..1d61b447
--- /dev/null
+++ b/apps/atrium-telegram/app/pages/ticket/index.vue
@@ -0,0 +1,22 @@
+
+
+
+
+ {{ ticket.title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/atrium-telegram/app/stores/ticket.ts b/apps/atrium-telegram/app/stores/ticket.ts
new file mode 100644
index 00000000..c665e257
--- /dev/null
+++ b/apps/atrium-telegram/app/stores/ticket.ts
@@ -0,0 +1,44 @@
+import type { Ticket, TicketMessage, User } from '@roll-stack/database'
+import { initDataRaw as _initDataRaw, useSignal } from '@telegram-apps/sdk-vue'
+
+export type TicketWithData = Ticket & {
+ messages: TicketMessage[]
+ lastMessage: TicketMessage | null
+ user: User
+}
+
+export const useTicketStore = defineStore('ticket', () => {
+ const tickets = ref([])
+
+ const initDataRaw = useSignal(_initDataRaw)
+
+ async function update() {
+ try {
+ const data = await $fetch('/api/ticket/list', {
+ headers: {
+ Authorization: `tma ${initDataRaw.value}`,
+ },
+ })
+ if (!data) {
+ return
+ }
+
+ tickets.value = data
+ } catch (error) {
+ if (error instanceof Error) {
+ if (error.message.includes('401')) {
+ // No session
+ }
+ if (error.message.includes('404')) {
+ // Not found
+ }
+ }
+ }
+ }
+
+ return {
+ tickets,
+
+ update,
+ }
+})
diff --git a/apps/atrium-telegram/i18n/locales/ru-RU.json b/apps/atrium-telegram/i18n/locales/ru-RU.json
index f0d89a6f..8a52519d 100644
--- a/apps/atrium-telegram/i18n/locales/ru-RU.json
+++ b/apps/atrium-telegram/i18n/locales/ru-RU.json
@@ -17,11 +17,13 @@
"send": "Отправить",
"upload": "Загрузить",
"detach": "Открепить",
- "select": "Выберите"
+ "select": "Выберите",
+ "show-more": "Показать еще"
},
"app": {
"flow": "Поток",
"epics": "Эпики",
+ "tickets": "Тикеты",
"my-tasks": "Мои задачи",
"resolution": "Резолюция",
"report": "Небольшой отчет",
diff --git a/apps/atrium-telegram/server/api/ticket/list.get.ts b/apps/atrium-telegram/server/api/ticket/list.get.ts
new file mode 100644
index 00000000..bf99512d
--- /dev/null
+++ b/apps/atrium-telegram/server/api/ticket/list.get.ts
@@ -0,0 +1,5 @@
+import { repository } from '@roll-stack/database'
+
+export default defineEventHandler(async () => {
+ return repository.ticket.listOpened()
+})
diff --git a/packages/database/src/repository/ticket.ts b/packages/database/src/repository/ticket.ts
index 7199bb91..74bacfb5 100644
--- a/packages/database/src/repository/ticket.ts
+++ b/packages/database/src/repository/ticket.ts
@@ -17,8 +17,11 @@ export class Ticket {
static async listOpened() {
return useDatabase().query.tickets.findMany({
where: (tickets, { eq }) => eq(tickets.status, 'opened'),
+ orderBy: (tickets, { desc }) => desc(tickets.updatedAt),
with: {
- messages: true,
+ messages: {
+ orderBy: (ticketMessages, { desc }) => desc(ticketMessages.createdAt),
+ },
lastMessage: true,
user: true,
},