first commit
This commit is contained in:
308
resources/frontend/core/components/ScreenshotModal.vue
Normal file
308
resources/frontend/core/components/ScreenshotModal.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<at-modal v-if="show" class="modal" :width="900" :value="true" @on-cancel="onClose" @on-confirm="onClose">
|
||||
<template v-slot:header>
|
||||
<span class="modal-title">{{ $t('field.screenshot') }}</span>
|
||||
</template>
|
||||
|
||||
<AppImage
|
||||
v-if="interval && interval.id && screenshotsEnabled"
|
||||
class="modal-screenshot"
|
||||
:src="getScreenshotPath(interval)"
|
||||
:openable="true"
|
||||
/>
|
||||
<i v-else class="icon icon-camera-off modal-screenshot" />
|
||||
<at-progress
|
||||
class="screenshot__activity-bar"
|
||||
:stroke-width="7"
|
||||
:percent="+(+interval.activity_fill / 2 || 0)"
|
||||
/>
|
||||
|
||||
<div v-if="showNavigation" class="modal-left">
|
||||
<at-button type="primary" icon="icon-arrow-left" @click="$emit('showPrevious')"></at-button>
|
||||
</div>
|
||||
|
||||
<div v-if="showNavigation" class="modal-right">
|
||||
<at-button type="primary" icon="icon-arrow-right" @click="$emit('showNext')"></at-button>
|
||||
</div>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div v-if="project" class="modal-field">
|
||||
<span class="modal-label">{{ $t('field.project') }}:</span>
|
||||
<span class="modal-value">
|
||||
<router-link :to="`/projects/view/${project.id}`">{{ project.name }}</router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="task" class="modal-field">
|
||||
<span class="modal-label">{{ $t('field.task') }}:</span>
|
||||
<span class="modal-value">
|
||||
<router-link :to="`/tasks/view/${task.id}`">{{ task.task_name }}</router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="user" class="modal-field">
|
||||
<span class="modal-label">{{ $t('field.user') }}:</span>
|
||||
<span class="modal-value">
|
||||
{{ user.full_name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="interval" class="modal-field">
|
||||
<span class="modal-label">{{ $t('field.created_at') }}:</span>
|
||||
<span class="modal-value">{{ formatDate(interval.start_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div v-if="interval.activity_fill === null" class="screenshot__activity">
|
||||
{{ $t('tooltip.activity_progress.not_tracked') }}
|
||||
</div>
|
||||
<div v-else class="screenshot__activity modal-field">
|
||||
<div class="modal-field">
|
||||
<span class="modal-label">{{ $tc('tooltip.activity_progress.overall', 0) }}</span>
|
||||
<span class="modal-value">
|
||||
{{ interval.activity_fill + '%' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="interval.mouse_fill !== null" class="modal-field">
|
||||
<span class="modal-label">
|
||||
{{ $t('tooltip.activity_progress.just_mouse') }}
|
||||
</span>
|
||||
|
||||
<span class="modal-value">
|
||||
{{ interval.mouse_fill + '%' }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="interval.keyboard_fill !== null" class="modal-field">
|
||||
<span class="modal-label">{{ $t('tooltip.activity_progress.just_keyboard') }}</span>
|
||||
<span class="modal-value">
|
||||
{{ interval.keyboard_fill + '%' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="interval" class="modal-duration modal-field">
|
||||
<span class="modal-label">{{ $t('field.duration') }}:</span>
|
||||
<span class="modal-value">{{
|
||||
$t('field.duration_value', [formatDate(interval.start_at), formatDate(interval.end_at)])
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="canRemove" class="row">
|
||||
<at-button class="modal-remove" type="text" icon="icon-trash-2" @click="onRemove" />
|
||||
</div>
|
||||
</template>
|
||||
</at-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment-timezone';
|
||||
import AppImage from './AppImage';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export function screenshotPathProvider(interval) {
|
||||
return `time-intervals/${interval.id}/screenshot`;
|
||||
}
|
||||
|
||||
export const config = { screenshotPathProvider };
|
||||
|
||||
export default {
|
||||
name: 'ScreenshotModal',
|
||||
components: {
|
||||
AppImage,
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
project: {
|
||||
type: Object,
|
||||
},
|
||||
task: {
|
||||
type: Object,
|
||||
},
|
||||
interval: {
|
||||
type: Object,
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
},
|
||||
showNavigation: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
canRemove: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('user', ['companyData']),
|
||||
...mapGetters('screenshots', { screenshotsEnabled: 'enabled' }),
|
||||
},
|
||||
methods: {
|
||||
formatDate(value) {
|
||||
return moment
|
||||
.utc(value)
|
||||
.tz(this.companyData.timezone, true)
|
||||
.locale(this.$i18n.locale)
|
||||
.format('MMMM D, YYYY — HH:mm:ss (Z)');
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
onRemove() {
|
||||
this.$emit('remove', this.interval.id);
|
||||
},
|
||||
getScreenshotPath(interval) {
|
||||
return config.screenshotPathProvider(interval);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal {
|
||||
&::v-deep {
|
||||
.pu-skeleton {
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
.at-modal__mask {
|
||||
background: rgba(#151941, 0.7);
|
||||
}
|
||||
|
||||
.at-modal__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
overflow-y: scroll;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.at-modal {
|
||||
border-radius: 15px;
|
||||
top: unset;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.at-modal__header {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.at-modal__body {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
.icon-camera-off {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.at-modal__footer {
|
||||
position: relative;
|
||||
border: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.at-modal__close {
|
||||
color: #b1b1be;
|
||||
}
|
||||
|
||||
.at-progress-bar {
|
||||
display: block;
|
||||
&__wraper,
|
||||
&__inner {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.at-progress__text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-left {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #000000;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&-screenshot {
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
height: auto;
|
||||
min-height: 300px;
|
||||
max-height: 70vh;
|
||||
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&-remove {
|
||||
position: absolute;
|
||||
|
||||
bottom: 12px;
|
||||
right: 16px;
|
||||
|
||||
color: #ff5569;
|
||||
}
|
||||
|
||||
&-field {
|
||||
color: #666;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
&-label {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
&-value,
|
||||
&-value a {
|
||||
color: #2e2ef9;
|
||||
}
|
||||
|
||||
&-duration {
|
||||
padding-right: 3em;
|
||||
}
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.modal ::v-deep .at-modal__wrapper {
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user