share with a png file
This commit is contained in:
@@ -15,16 +15,10 @@ const { duration } = useTaskRecordMetadata(taskRecord)
|
||||
|
||||
<template>
|
||||
<div class="task-record-preview">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'record-view',
|
||||
params: { taskId }
|
||||
}"
|
||||
class="button is-primary is-light"
|
||||
>start session</router-link
|
||||
>
|
||||
<div v-if="duration !== null">Last record took {{ duration }} minutes</div>
|
||||
<div v-else>No record yet</div>
|
||||
<div v-if="taskRecord !== null">
|
||||
Last record took {{ duration }} minutes.
|
||||
</div>
|
||||
<div v-else>No record yet.</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,44 +1,45 @@
|
||||
import { useTaskRecordStore } from '@/modules/record/stores/useTaskRecordStore'
|
||||
import type { Task } from '@/modules/task/models/task'
|
||||
import { formatDiffInMinutes, formatToShortDate } from '@/shared/format-date'
|
||||
import { toValue } from '@vueuse/core'
|
||||
import { ref, type ComputedRef } from 'vue'
|
||||
import { computed, ref, type ComputedRef } from 'vue'
|
||||
import { toBlob } from 'html-to-image'
|
||||
|
||||
export const useCopyRecord = (task: ComputedRef<Task | null>) => {
|
||||
const recordStore = useTaskRecordStore()
|
||||
|
||||
const canShareTask = !!navigator.clipboard
|
||||
const canShareTask =
|
||||
!!navigator && !!navigator.clipboard && !!navigator.clipboard.writeText
|
||||
const taskCopied = ref(false)
|
||||
const domId = computed(() => `task-${task.value?.id}`)
|
||||
|
||||
const shareTask = async () => {
|
||||
const t = toValue(task)
|
||||
const node = document.getElementById(domId.value)
|
||||
|
||||
if (!t) {
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
|
||||
const record = recordStore.getTaskRecord(t.id)
|
||||
|
||||
let clipboardText = `${t.title};${formatToShortDate(t.date)}\n
|
||||
Step;Estimation;Duration\n`
|
||||
|
||||
t.steps.forEach((step) => {
|
||||
const recordStep = record?.stepRecords[step.id]
|
||||
const duration =
|
||||
recordStep && recordStep.end
|
||||
? formatDiffInMinutes(recordStep.start, recordStep.end)
|
||||
: '-'
|
||||
const analyze = duration <= step.estimation ? '✅' : '⚠️'
|
||||
|
||||
clipboardText += `"${analyze} ${step.title}";${step.estimation};${duration}\n`
|
||||
const blob = await toBlob(node, {
|
||||
style: {
|
||||
margin: 'inherit'
|
||||
}
|
||||
})
|
||||
|
||||
await navigator.clipboard.writeText(clipboardText)
|
||||
taskCopied.value = true
|
||||
if (!blob) {
|
||||
return
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
taskCopied.value = false
|
||||
}, 2000)
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob
|
||||
})
|
||||
])
|
||||
|
||||
taskCopied.value = true
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
taskCopied.value = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useCopyRecord } from '@/modules/record/hooks/useCopyRecord.hook'
|
||||
import { useTaskStore } from '@/modules/task/stores/useTask.store'
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import StepRecord from '@/modules/record/components/StepRecord.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
id: string
|
||||
@@ -31,47 +32,78 @@ const { canShareTask, taskCopied, shareTask } = useCopyRecord(task)
|
||||
<template>
|
||||
<div class="task-view" v-if="task">
|
||||
<div class="buttons actions">
|
||||
<router-link :to="{
|
||||
name: 'edit-task',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
}" class="button">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'record-view',
|
||||
params: { taskId: id }
|
||||
}"
|
||||
class="button is-primary is-light"
|
||||
>start session</router-link
|
||||
>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'edit-task',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
}"
|
||||
class="button"
|
||||
>
|
||||
<img src="/icons/edit.svg" alt="edit task" />
|
||||
</router-link>
|
||||
<button v-if="canShareTask" class="share-task button" @click="shareTask">
|
||||
<img v-if="taskCopied" src="/icons/check.svg" alt="task copied!" />
|
||||
<img v-else src="/icons/share.svg" alt="share task" />
|
||||
</button>
|
||||
<router-link :to="{
|
||||
name: 'duplicate-task',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
}" class="button">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'duplicate-task',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
}"
|
||||
class="button"
|
||||
>
|
||||
<img src="/icons/copy.svg" alt="duplicate task" />
|
||||
</router-link>
|
||||
<button class="delete-task button is-light is-danger" @click="deleteTask">
|
||||
<img src="/icons/trash.svg" alt="delete task" />
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="title">{{ task.title }}</h1>
|
||||
<h2 class="subtitle">
|
||||
<estimation-time-arrival :estimation="task.totalEstimation" />
|
||||
</h2>
|
||||
<a v-if="task.link" :href="task.link" target="_blank" rel="noopener noreferrer" class="button is-link">user story
|
||||
link</a>
|
||||
<task-record-preview :task-id="id" />
|
||||
<hr />
|
||||
<div class="content">
|
||||
<ol>
|
||||
<li v-for="step in task.steps" :key="step.id">
|
||||
<div class="step-item">
|
||||
<span>{{ step.title }}</span>
|
||||
<span class="tag">{{ step.estimation }} minutes</span>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
<a
|
||||
v-if="task.link"
|
||||
:href="task.link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="button is-link"
|
||||
>user story link</a
|
||||
>
|
||||
<div class="content" :id="`task-${id}`">
|
||||
<h1 class="title">{{ task.title }}</h1>
|
||||
<h2 class="subtitle">
|
||||
<estimation-time-arrival :estimation="task.totalEstimation" />
|
||||
</h2>
|
||||
<task-record-preview :task-id="id" />
|
||||
<table class="table is-striped is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>status</th>
|
||||
<th>task</th>
|
||||
<th>estimation</th>
|
||||
<th>actual</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<step-record
|
||||
v-for="(step, key) in task.steps"
|
||||
:task-id="id"
|
||||
:key="step.id"
|
||||
:step-id="step.id"
|
||||
:step-number="key + 1"
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<task-not-found v-else />
|
||||
@@ -89,4 +121,11 @@ const { canShareTask, taskCopied, shareTask } = useCopyRecord(task)
|
||||
.actions {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: white;
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user