♻️ (record) one task is now one record

This commit is contained in:
Julien Calixte
2023-04-15 23:15:24 +02:00
parent f890012179
commit d506a0e956
13 changed files with 80 additions and 116 deletions

View File

@@ -8,14 +8,13 @@ import { useTaskRecordStore } from '../stores/useTaskRecordStore'
const props = defineProps<{ const props = defineProps<{
taskId: string taskId: string
recordId: string
}>() }>()
const taskStore = useTaskStore() const taskStore = useTaskStore()
const recordStore = useTaskRecordStore() const recordStore = useTaskRecordStore()
const task = computed(() => taskStore.getTask(props.taskId)) const task = computed(() => taskStore.getTask(props.taskId))
const record = computed(() => recordStore.getTaskRecord(props.recordId)) const record = computed(() => recordStore.getTaskRecord(props.taskId))
const getNextStepId = () => { const getNextStepId = () => {
if (!task.value) { if (!task.value) {
@@ -53,7 +52,7 @@ const startRecording = () => {
} }
recordStore.startStepRecord({ recordStore.startStepRecord({
recordId: props.recordId, taskId: props.taskId,
stepId: task.value.steps[0].id, stepId: task.value.steps[0].id,
start: toISODate(new Date()) start: toISODate(new Date())
}) })
@@ -65,7 +64,7 @@ const nextStep = () => {
} }
recordStore.nextStepRecord({ recordStore.nextStepRecord({
recordId: record.value.id, taskId: record.value.taskId,
currentStepId: recordStore.currentStepId, currentStepId: recordStore.currentStepId,
nextStepId: getNextStepId(), nextStepId: getNextStepId(),
tick: toISODate(new Date()) tick: toISODate(new Date())
@@ -98,7 +97,7 @@ whenever(logicAnd(notUsingInput, s), () => {
<button class="button" v-else @click="nextStep">next</button> <button class="button" v-else @click="nextStep">next</button>
</template> </template>
<button class="button is-warning" @click="recordStore.reset(recordId)"> <button class="button is-warning" @click="recordStore.reset(taskId)">
reset reset
</button> </button>
</div> </div>

View File

@@ -5,14 +5,13 @@ import { useTaskRecordStore } from '../stores/useTaskRecordStore'
const props = defineProps<{ const props = defineProps<{
taskId: string taskId: string
recordId: string
}>() }>()
const taskStore = useTaskStore() const taskStore = useTaskStore()
const taskRecordStore = useTaskRecordStore() const taskRecordStore = useTaskRecordStore()
const task = computed(() => taskStore.getTask(props.taskId)) const task = computed(() => taskStore.getTask(props.taskId))
const record = computed(() => taskRecordStore.getRecord(props.recordId)) const record = computed(() => taskRecordStore.getRecord(props.taskId))
const numberOfFinishedSteps = computed( const numberOfFinishedSteps = computed(
() => () =>

View File

@@ -7,7 +7,6 @@ import { useTaskRecordStore } from '../stores/useTaskRecordStore'
const props = defineProps<{ const props = defineProps<{
taskId: string taskId: string
recordId: string
stepId: string stepId: string
stepNumber: number stepNumber: number
}>() }>()
@@ -17,7 +16,7 @@ const recordStore = useTaskRecordStore()
const step = computed(() => taskStore.getStep(props.taskId, props.stepId)) const step = computed(() => taskStore.getStep(props.taskId, props.stepId))
const stepRecord = computed(() => const stepRecord = computed(() =>
recordStore.getStepRecord(props.recordId, props.stepId) recordStore.getStepRecord(props.taskId, props.stepId)
) )
const isCurrentStep = computed(() => recordStore.currentStepId === props.stepId) const isCurrentStep = computed(() => recordStore.currentStepId === props.stepId)

View File

@@ -11,20 +11,19 @@ import StepRecord from './StepRecord.vue'
const props = defineProps<{ const props = defineProps<{
taskId: string taskId: string
recordId: string
}>() }>()
const taskStore = useTaskStore() const taskStore = useTaskStore()
const recordStore = useTaskRecordStore() const recordStore = useTaskRecordStore()
recordStore.addRecord(props.taskId, props.recordId) recordStore.addRecord(props.taskId)
const task = computed(() => taskStore.getTask(props.taskId)) const task = computed(() => taskStore.getTask(props.taskId))
useLoopyTitle(task.value?.title ?? '') useLoopyTitle(task.value?.title ?? '')
const record = computed(() => recordStore.getTaskRecord(props.recordId)) const record = computed(() => recordStore.getTaskRecord(props.taskId))
const recordNotes = computed(() => recordStore.getRecordNotes(props.recordId)) const recordNotes = computed(() => recordStore.getRecordNotes(props.taskId))
const { duration } = useTaskRecordMetadata(record) const { duration } = useTaskRecordMetadata(record)
const isSuperiorToEstimation = computed(() => { const isSuperiorToEstimation = computed(() => {
@@ -38,7 +37,7 @@ const isSuperiorToEstimation = computed(() => {
<template> <template>
<main class="task-record" v-if="task"> <main class="task-record" v-if="task">
<record-progress :task-id="taskId" :record-id="recordId" /> <record-progress :task-id="taskId" />
<h1 class="title"> <h1 class="title">
<router-link <router-link
:to="{ name: 'task-view', params: { id: task.id } }" :to="{ name: 'task-view', params: { id: task.id } }"
@@ -48,7 +47,7 @@ const isSuperiorToEstimation = computed(() => {
</router-link> </router-link>
</h1> </h1>
<h2 class="subtitle" v-if="record">{{ formatLongDate(record.start) }}</h2> <h2 class="subtitle" v-if="record">{{ formatLongDate(record.start) }}</h2>
<record-controls :task-id="taskId" :record-id="recordId" /> <record-controls :task-id="taskId" />
<table class="table is-striped is-hoverable is-fullwidth"> <table class="table is-striped is-hoverable is-fullwidth">
<thead> <thead>
<tr> <tr>
@@ -63,7 +62,6 @@ const isSuperiorToEstimation = computed(() => {
<step-record <step-record
v-for="(step, key) in task.steps" v-for="(step, key) in task.steps"
:task-id="taskId" :task-id="taskId"
:record-id="recordId"
:key="step.id" :key="step.id"
:step-id="step.id" :step-id="step.id"
:step-number="key + 1" :step-number="key + 1"

View File

@@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { formatDate } from '@/shared/format-date'
import { useTaskRecordMetadata } from '../hooks/useTaskRecordMetadata' import { useTaskRecordMetadata } from '../hooks/useTaskRecordMetadata'
import type { TaskRecord } from '../models/task-record' import type { TaskRecord } from '../models/task-record'
@@ -12,15 +11,7 @@ const { duration } = useTaskRecordMetadata(props.record)
<template> <template>
<div class="task-record-link-container content"> <div class="task-record-link-container content">
<router-link <span v-if="duration !== null">last time: {{ duration }} minutes </span>
class="task-record-link button is-outlined"
:to="{
name: 'record-view',
params: { taskId: record.taskId, recordId: record.id }
}"
>{{ formatDate(record.start) }}</router-link
>
<span v-if="duration !== null"> {{ duration }} minutes </span>
</div> </div>
</template> </template>

View File

@@ -1,41 +0,0 @@
<script setup lang="ts">
import { createUuid } from '@/shared/create-uuid'
import { computed } from 'vue'
import { useTaskRecordStore } from '../stores/useTaskRecordStore'
import TaskRecordLink from './TaskRecordLink.vue'
const props = defineProps<{
taskId: string
}>()
const recordStore = useTaskRecordStore()
const recordsFromLastToFirst = computed(() =>
recordStore
.getTaskRecords(props.taskId)
.sort((a, b) => (a.start > b.start ? -1 : 1))
)
const newRecordId = createUuid()
</script>
<template>
<div>
<div class="content">
<h3 class="subtitle is-4">Records</h3>
<ol v-if="recordsFromLastToFirst.length" class="task-record-list">
<li v-for="record in recordsFromLastToFirst" :key="record.id">
<task-record-link :record="record" />
</li>
</ol>
<div v-else>No record yet</div>
</div>
<router-link
:to="{
name: 'record-view',
params: { taskId, recordId: newRecordId }
}"
class="button is-primary is-light"
>start a new record</router-link
>
</div>
</template>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useTaskRecordStore } from '../stores/useTaskRecordStore'
import TaskRecordDuration from './TaskRecordDuration.vue'
const props = defineProps<{
taskId: string
}>()
const recordStore = useTaskRecordStore()
const taskRecord = computed(() => recordStore.getTaskRecord(props.taskId))
</script>
<template>
<div>
<div class="content">
<h3 class="subtitle is-4">Record</h3>
<task-record-duration v-if="taskRecord" :record="taskRecord" />
<div v-else>No record yet</div>
</div>
<router-link
:to="{
name: 'record-view',
params: { taskId }
}"
class="button is-primary is-light"
>start the record</router-link
>
</div>
</template>

View File

@@ -2,7 +2,6 @@ import type { ISODate } from '@/shared/types/date'
import type { StepRecordable } from './step-recordable' import type { StepRecordable } from './step-recordable'
export interface Recordable { export interface Recordable {
id: string
taskId: string taskId: string
/** /**
* @deprecated * @deprecated

View File

@@ -8,17 +8,14 @@ export class TaskRecord implements Recordable {
public stepRecords: Record<string, StepRecordable> = {} public stepRecords: Record<string, StepRecordable> = {}
public notes = '' public notes = ''
public constructor( public constructor(public readonly taskId: string) {}
public readonly id: string,
public readonly taskId: string
) {}
public get hasStepRecords() { public get hasStepRecords() {
return Object.values(this.stepRecords).length > 0 return Object.values(this.stepRecords).length > 0
} }
public static fromRecordable(recordable: Recordable) { public static fromRecordable(recordable: Recordable) {
const taskRecord = new TaskRecord(recordable.id, recordable.taskId) const taskRecord = new TaskRecord(recordable.taskId)
taskRecord.stepRecords = recordable.stepRecords taskRecord.stepRecords = recordable.stepRecords
taskRecord.start = recordable.start taskRecord.start = recordable.start

View File

@@ -16,21 +16,22 @@ export const useTaskRecordStore = defineStore('task-record-store', {
records: {} records: {}
}), }),
actions: { actions: {
addRecord(taskId: string, recordId: string) { addRecord(taskId: string) {
if (recordId in this.records) { if (taskId in this.records) {
return return
} }
this.records[recordId] = new TaskRecord(recordId, taskId)
this.records[taskId] = new TaskRecord(taskId)
}, },
removeRecord(recordId: string) { removeRecord(taskId: string) {
delete this.records[recordId] delete this.records[taskId]
}, },
startStepRecord(params: { startStepRecord(params: {
recordId: string taskId: string
stepId: string stepId: string
start: ISODate start: ISODate
}) { }) {
const record = this.records[params.recordId] const record = this.records[params.taskId]
if (Object.values(record.stepRecords).length === 0) { if (Object.values(record.stepRecords).length === 0) {
record.start = params.start record.start = params.start
@@ -39,7 +40,7 @@ export const useTaskRecordStore = defineStore('task-record-store', {
this.$patch({ this.$patch({
records: { records: {
...this.records, ...this.records,
[params.recordId]: { [params.taskId]: {
...record, ...record,
stepRecords: { stepRecords: {
...record.stepRecords, ...record.stepRecords,
@@ -52,9 +53,8 @@ export const useTaskRecordStore = defineStore('task-record-store', {
currentStepId: params.stepId currentStepId: params.stepId
}) })
}, },
endStepRecord(params: { recordId: string; stepId: string; end: ISODate }) { endStepRecord(params: { taskId: string; stepId: string; end: ISODate }) {
const stepRecord = const stepRecord = this.records[params.taskId]?.stepRecords[params.stepId]
this.records[params.recordId]?.stepRecords[params.stepId]
if (!stepRecord) { if (!stepRecord) {
return return
@@ -63,44 +63,44 @@ export const useTaskRecordStore = defineStore('task-record-store', {
stepRecord.end = params.end stepRecord.end = params.end
}, },
nextStepRecord(params: { nextStepRecord(params: {
recordId: string taskId: string
currentStepId: string currentStepId: string
nextStepId: string | null nextStepId: string | null
tick: ISODate tick: ISODate
}) { }) {
this.endStepRecord({ this.endStepRecord({
recordId: params.recordId, taskId: params.taskId,
stepId: params.currentStepId, stepId: params.currentStepId,
end: params.tick end: params.tick
}) })
if (!params.nextStepId) { if (!params.nextStepId) {
this.endRecord(params.recordId) this.endRecord(params.taskId)
return return
} }
this.startStepRecord({ this.startStepRecord({
recordId: params.recordId, taskId: params.taskId,
stepId: params.nextStepId, stepId: params.nextStepId,
start: params.tick start: params.tick
}) })
}, },
endRecord(recordId: string) { endRecord(taskId: string) {
if (!this.records[recordId]) { if (!this.records[taskId]) {
return return
} }
this.records[recordId].end = toISODate(new Date()) this.records[taskId].end = toISODate(new Date())
this.currentStepId = null this.currentStepId = null
}, },
updateRecordNotes(recordId: string, notes: string) { updateRecordNotes(taskId: string, notes: string) {
const record = this.records[recordId] const record = this.records[taskId]
if (record) { if (record) {
this.$patch({ this.$patch({
records: { records: {
...this.records, ...this.records,
[recordId]: { [taskId]: {
...record, ...record,
notes notes
} }
@@ -108,43 +108,36 @@ export const useTaskRecordStore = defineStore('task-record-store', {
}) })
} }
}, },
reset(recordId: string) { reset(taskId: string) {
this.currentStepId = null this.currentStepId = null
if (!this.records[recordId]) { if (!this.records[taskId]) {
return return
} }
this.records[recordId].stepRecords = {} this.records[taskId].stepRecords = {}
this.records[recordId].end = undefined this.records[taskId].end = undefined
} }
}, },
getters: { getters: {
getTaskRecords() {
return (taskId: string): TaskRecord[] =>
Object.values(this.records)
.filter((record) => record.taskId === taskId)
.map((record) => TaskRecord.fromRecordable(record))
},
getTaskRecord() { getTaskRecord() {
return (recordId: string): TaskRecord | null => { return (taskId: string): TaskRecord | null => {
const hasTaskRecord = !!this.records[recordId] const hasTaskRecord = !!this.records[taskId]
if (hasTaskRecord) { if (hasTaskRecord) {
return TaskRecord.fromRecordable(this.records[recordId]) return TaskRecord.fromRecordable(this.records[taskId])
} }
return null return null
} }
}, },
getRecord() { getRecord() {
return (recordId: string): Recordable | null => return (taskId: string): Recordable | null => this.records[taskId] ?? null
this.records[recordId] ?? null
}, },
getStepRecord() { getStepRecord() {
return (recordId: string, stepId: string): StepRecordable | null => return (taskId: string, stepId: string): StepRecordable | null =>
this.records[recordId]?.stepRecords[stepId] ?? null this.records[taskId]?.stepRecords[stepId] ?? null
}, },
getRecordNotes() { getRecordNotes() {
return (recordId: string): string => this.records[recordId]?.notes ?? '' return (taskId: string): string => this.records[taskId]?.notes ?? ''
} }
} }
}) })

View File

@@ -26,7 +26,7 @@ export const router = createRouter({
component: () => import('../views/task/TaskView.vue') component: () => import('../views/task/TaskView.vue')
}, },
{ {
path: '/task/:taskId/records/:recordId', path: '/task/:taskId/record',
name: 'record-view', name: 'record-view',
props: true, props: true,
component: () => import('../views/record/RecordView.vue') component: () => import('../views/record/RecordView.vue')

View File

@@ -3,12 +3,11 @@ import TaskRecord from '@/modules/record/components/TaskRecord.vue'
defineProps<{ defineProps<{
taskId: string taskId: string
recordId: string
}>() }>()
</script> </script>
<template> <template>
<div class="record-view"> <div class="record-view">
<TaskRecord :task-id="taskId" :record-id="recordId" /> <TaskRecord :task-id="taskId" />
</div> </div>
</template> </template>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import TaskRecordList from '@/modules/record/components/TaskRecordList.vue' import TaskRecordList from '@/modules/record/components/TaskRecordPreview.vue'
import { useTaskStore } from '@/modules/task/stores/useTask.store' import { useTaskStore } from '@/modules/task/stores/useTask.store'
import { computed } from 'vue' import { computed } from 'vue'