123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
import {
|
|
type CreateIssueInput,
|
|
type Issue,
|
|
type DailyIssueStats,
|
|
itemCreate,
|
|
itemDailyStat,
|
|
itemDelete,
|
|
itemGetByKey,
|
|
itemsList,
|
|
itemStat,
|
|
itemUpdate,
|
|
type IssueStat,
|
|
type Meta,
|
|
type UpdateIssueInput,
|
|
} from '@/api/issue.api.ts'
|
|
|
|
export const useIssueStore = defineStore('item', () => {
|
|
const issues = ref<Issue[]>([])
|
|
const stats = ref<IssueStat>()
|
|
const dailyStats = ref<DailyIssueStats>()
|
|
const error = ref<string | null>(null)
|
|
const lastMeta = ref<Meta>({
|
|
page: 1,
|
|
totalCount: 0,
|
|
totalPages: 0,
|
|
})
|
|
|
|
async function list(params: {
|
|
page: number
|
|
limit: number
|
|
text?: string | null
|
|
status?: string | string[] | null
|
|
assigneeId?: string | null
|
|
projectId?: string | null
|
|
}) {
|
|
try {
|
|
const res = await itemsList(params)
|
|
issues.value = res.list
|
|
return res
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error get list of items'
|
|
return { list: [], meta: lastMeta.value }
|
|
}
|
|
}
|
|
|
|
async function getByKey(ckey: string) {
|
|
try {
|
|
return await itemGetByKey(ckey)
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error get item by key'
|
|
}
|
|
}
|
|
|
|
async function create(input: CreateIssueInput) {
|
|
try {
|
|
return await itemCreate(input)
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error creating issue'
|
|
}
|
|
}
|
|
|
|
async function update(id: number, input: UpdateIssueInput) {
|
|
try {
|
|
return await itemUpdate(id, input)
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error updating issue'
|
|
}
|
|
}
|
|
|
|
async function remove(id: number) {
|
|
try {
|
|
return await itemDelete(id)
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error deleting issue'
|
|
return false
|
|
}
|
|
}
|
|
|
|
async function getStat(projectId?: string | null): Promise<IssueStat | undefined> {
|
|
try {
|
|
stats.value = await itemStat(projectId ?? undefined)
|
|
|
|
return stats.value
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error getting issue stat'
|
|
}
|
|
}
|
|
|
|
let dailyStatsRequestId = 0
|
|
|
|
/** Stats for the last `days` days including today, in the user's local time zone */
|
|
async function getDailyStat(projectId?: string | null, days = 30): Promise<DailyIssueStats | undefined> {
|
|
// Ignore responses that arrive after the project or period has changed again
|
|
const requestId = ++dailyStatsRequestId
|
|
try {
|
|
const res = await itemDailyStat({
|
|
projectId: projectId ?? undefined,
|
|
from: localDateDaysAgo(days - 1),
|
|
// Day boundaries are computed on the backend in the user's local time zone; `to` defaults to today there
|
|
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
})
|
|
if (requestId !== dailyStatsRequestId) return
|
|
dailyStats.value = res
|
|
|
|
return dailyStats.value
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : 'error getting daily issue stat'
|
|
}
|
|
}
|
|
|
|
return { stats, dailyStats, list, getByKey, create, update, remove, getStat, getDailyStat }
|
|
})
|
|
|
|
/** Local YYYY-MM-DD `days` days before today */
|
|
function localDateDaysAgo(days: number): string {
|
|
const date = new Date()
|
|
date.setDate(date.getDate() - days)
|
|
const pad = (value: number) => String(value).padStart(2, '0')
|
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
|
|
}
|