cattr-app/frontend-application

View on GitHub
app/core/components/ScreenshotModal.vue

Summary

Maintainability
Test Coverage
<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"
            class="modal-screenshot"
            :src="getScreenshotPath(interval)"
            :openable="true"
        />
        <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']),
        },
        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;
            }

            .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;
        }
    }
</style>