pixelfed/pixelfed

View on GitHub
resources/assets/js/components/Direct.vue

Summary

Maintainability
Test Coverage
<template>
<div>
    <div v-if="loaded && page == 'browse'" class="container messages-page p-0 p-md-2 mt-n4" style="min-height: 50vh;">
        <div class="col-12 col-md-8 offset-md-2 p-0 px-md-2">
            <div class="card shadow-none border mt-4">
                <div class="card-header bg-white py-4">
                    <span class="h4 font-weight-bold mb-0">Direct Messages</span>
                    <span class="float-right">
                        <a class="btn btn-outline-primary font-weight-bold py-0 rounded-pill" href="#" @click.prevent="goto('add')">New Message</a>
                    </span>
                </div>
                <div class="card-header bg-white">
                    <ul class="nav nav-pills nav-fill">
                        <li class="nav-item">
                            <a :class="[tab == 'inbox' ? 'nav-link px-4 font-weight-bold rounded-pill active' : 'nav-link px-4 font-weight-bold rounded-pill']" @click.prevent="switchTab('inbox')" href="#">Inbox</a>
                        </li>
                        <li class="nav-item">
                            <a :class="[tab == 'sent' ? 'nav-link px-4 font-weight-bold rounded-pill active' : 'nav-link px-4 font-weight-bold rounded-pill']" @click.prevent="switchTab('sent')" href="#">Sent</a>
                        </li>
                        <li class="nav-item">
                            <a :class="[tab == 'filtered' ? 'nav-link px-4 font-weight-bold rounded-pill active' : 'nav-link px-4 font-weight-bold rounded-pill']" @click.prevent="switchTab('filtered')" href="#">Filtered</a>
                        </li>
                    </ul>
                </div>
                <ul v-if="tab == 'inbox'" class="list-group list-group-flush">
                    <div v-if="!messages.inbox.length" class="list-group-item d-flex justify-content-center align-items-center" style="min-height: 40vh;">
                        <p class="lead mb-0">No messages found :(</p>
                    </div>
                    <div v-else v-for="(thread, index) in messages.inbox" :key="'dm_inbox'+index">
                        <a class="list-group-item text-dark text-decoration-none border-left-0 border-right-0 border-top-0" :href="'/account/direct/t/'+thread.id">
                        <div class="media d-flex align-items-center">
                            <img class="mr-3 rounded-circle img-thumbnail" :src="thread.avatar" width="32" onerror="this.onerror=null;this.src='/storage/avatars/default.jpg';" v-once>
                            <div class="media-body">
                                <p class="mb-0">
                                    <span class="font-weight-bold text-truncate">
                                        {{thread.name}}
                                    </span>
                                    <span class="pl-1 text-muted small text-truncate" style="font-weight: 500;">
                                        {{thread.isLocal ? '@' + thread.username : thread.username}}
                                    </span>
                                </p>
                                <p class="text-muted mb-0" style="font-size:13px;font-weight: 500;">
                                    <span>
                                        <i class="far fa-comment text-primary"></i> 
                                    </span>
                                    <span class="pl-1 pr-3">
                                        Received
                                    </span>
                                    <span>
                                        {{thread.timeAgo}}
                                    </span>
                                </p>
                            </div>
                            <span class="float-right">
                                <i class="fas fa-chevron-right fa-lg text-lighter"></i>
                            </span>
                        </div>
                        </a>
                    </div>
                </ul>
                <ul v-if="tab == 'sent'" class="list-group list-group-flush">
                    <div v-if="!messages.sent.length" class="list-group-item d-flex justify-content-center align-items-center" style="min-height: 40vh;">
                        <p class="lead mb-0">No messages found :(</p>
                    </div>
                    <div v-else v-for="(thread, index) in messages.sent" :key="'dm_sent'+index">
                        <a class="list-group-item text-dark text-decoration-none border-left-0 border-right-0 border-top-0" href="#" @click.prevent="loadMessage(thread.id)">
                        <div class="media d-flex align-items-center">
                            <img class="mr-3 rounded-circle img-thumbnail" :src="thread.avatar" width="32" onerror="this.onerror=null;this.src='/storage/avatars/default.jpg';" v-once>
                            <div class="media-body">
                                <p class="mb-0">
                                    <span class="font-weight-bold text-truncate">
                                        {{thread.name}}
                                    </span>
                                    <span class="pl-1 text-muted small text-truncate" style="font-weight: 500;">
                                        {{thread.isLocal ? '@' + thread.username : thread.username}}
                                    </span>
                                </p>
                                <p class="text-muted mb-0" style="font-size:13px;font-weight: 500;">
                                    <span>
                                        <i class="far fa-paper-plane text-primary"></i> 
                                    </span>
                                    <span class="pl-1 pr-3">
                                        Delivered
                                    </span>
                                    <span>
                                        {{thread.timeAgo}}
                                    </span>
                                </p>
                            </div>
                            <span class="float-right">
                                <i class="fas fa-chevron-right fa-lg text-lighter"></i>
                            </span>
                        </div>
                        </a>
                    </div>
                </ul>
                <ul v-if="tab == 'filtered'" class="list-group list-group-flush">
                    <div v-if="!messages.filtered.length" class="list-group-item d-flex justify-content-center align-items-center" style="min-height: 40vh;">
                        <p class="lead mb-0">No messages found :(</p>
                    </div>
                    <div v-else v-for="(thread, index) in messages.filtered" :key="'dm_filtered'+index">
                        <a class="list-group-item text-dark text-decoration-none border-left-0 border-right-0 border-top-0" href="#" @click.prevent="loadMessage(thread.id)">
                        <div class="media d-flex align-items-center">
                            <img class="mr-3 rounded-circle img-thumbnail" :src="thread.avatar" width="32" onerror="this.onerror=null;this.src='/storage/avatars/default.jpg';" v-once>
                            <div class="media-body">
                                <p class="mb-0">
                                    <span class="font-weight-bold text-truncate">
                                        {{thread.name}}
                                    </span>
                                    <span class="pl-1 text-muted small text-truncate" style="font-weight: 500;">
                                        {{thread.isLocal ? '@' + thread.username : thread.username}}
                                    </span>
                                </p>
                                <p class="text-muted mb-0" style="font-size:13px;font-weight: 500;">
                                    <span>
                                        <i class="fas fa-shield-alt" style="color:#fd9426"></i> 
                                    </span>
                                    <span class="pl-1 pr-3">
                                        Filtered
                                    </span>
                                    <span>
                                        {{thread.timeAgo}}
                                    </span>
                                </p>
                            </div>
                            <span class="float-right">
                                <i class="fas fa-chevron-right fa-lg text-lighter"></i>
                            </span>
                        </div>
                        </a>
                    </div>
                </ul>
            </div>
            <div v-if="tab == 'inbox'" class="mt-3 text-center">
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="inboxPage == 1" @click="messagePagination('inbox', 'prev')">Prev</button>
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="messages.inbox.length != 8" @click="messagePagination('inbox', 'next')">Next</button>
            </div>
            <div v-if="tab == 'sent'" class="mt-3 text-center">
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="sentPage == 1" @click="messagePagination('sent', 'prev')">Prev</button>
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="messages.sent.length != 8" @click="messagePagination('sent', 'next')">Next</button>
            </div>
            <div v-if="tab == 'filtered'" class="mt-3 text-center">
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="filteredPage == 1" @click="messagePagination('filtered', 'prev')">Prev</button>
                <button class="btn btn-outline-primary rounded-pill btn-sm" :disabled="messages.filtered.length != 8" @click="messagePagination('filtered', 'next')">Next</button>
            </div>
        </div>
    </div>

    <div v-if="loaded && page == 'add'" class="container messages-page p-0 p-md-2 mt-n4" style="min-height: 60vh;">
        <div class="col-12 col-md-8 offset-md-2 p-0 px-md-2">
            <div class="card shadow-none border mt-4">
                <div class="card-header bg-white py-4 d-flex justify-content-between">
                    <span class="cursor-pointer px-3" @click="goto('browse')"><i class="fas fa-chevron-left"></i></span>
                    <span class="h4 font-weight-bold mb-0">New Direct Message</span>
                    <span><i class="fas fa-chevron-right text-white"></i></span>
                </div>
                <div class="card-body d-flex align-items-center justify-content-center" style="height: 60vh;">
                    <div>
                        <p class="mb-0 font-weight-bold">Select Recipient</p>
                        <autocomplete 
                            :search="composeSearch"
                            :disabled="composeLoading"
                            placeholder="@dansup"
                            aria-label="Search usernames"
                            :get-result-value="getTagResultValue"
                            @submit="onTagSubmitLocation"
                            ref="autocomplete"
                        >
                        </autocomplete>
                        <div style="width:300px;"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</template>

<style type="text/css" scoped>
</style>

<script type="text/javascript">
import Autocomplete from '@trevoreyre/autocomplete-vue'
import '@trevoreyre/autocomplete-vue/dist/style.css'
export default {
    components: { 
        Autocomplete 
    },
    data() {
        return {
            config: window.App.config,
            loaded: false,
            profile: {},
            page: 'browse',
            pages: ['browse', 'add', 'read'],
            tab: 'inbox',
            tabs: ['inbox', 'sent', 'filtered'],
            inboxPage: 1,
            sentPage: 1,
            filteredPage: 1,
            threads: [],
            thread: false,
            threadIndex: false,

            replyText: '',
            composeUsername: '',

            ctxContext: null,
            ctxIndex: null,

            uploading: false,
            uploadProgress: null,

            messages: {
                inbox: [],
                sent: [],
                filtered: []
            },

            newType: 'select',
            composeLoading: false,
        }
    },

    mounted() {
        this.fetchProfile();
        let self = this;
        axios.get('/api/direct/browse', {
            params: {
                a: 'inbox'
            }
        })
        .then(res => {
            self.loaded = true;
            this.threads = res.data
            this.messages.inbox = res.data;
        });
    },

    updated() {
        $('[data-toggle="tooltip"]').tooltip();
    },

    methods: {
        fetchProfile() {
            axios.get('/api/pixelfed/v1/accounts/verify_credentials').then(res => {
                this.profile = res.data;
                window._sharedData.curUser = res.data;
                window.App.util.navatar();
            });
        },

        goto(l = 'browse') {
            this.page = l;
        },

        loadMessage(id) {
            let url = '/account/direct/t/' + id;
            window.location.href = url;
            return;
        },

        truncate(t) {
            return _.truncate(t);
        },

        switchTab(tab) {
            let self = this;
            switch(tab) {
                case 'inbox':
                    if(this.messages.inbox.length == 0) {
                        // fetch
                    }
                break;
                case 'sent':
                if(this.messages.sent.length == 0) {
                    axios.get('/api/direct/browse', {
                        params: {
                            a: 'sent'
                        }
                    })
                    .then(res => {
                        self.loaded = true;
                        self.threads = res.data
                        self.messages.sent = res.data;
                    });
                }
                break;
                case 'filtered':
                    if(this.messages.filtered.length == 0) {
                        axios.get('/api/direct/browse', {
                            params: {
                                a: 'filtered'
                            }
                        })
                        .then(res => {
                            self.loaded = true;
                            self.threads = res.data
                            self.messages.filtered = res.data;
                        });
                    }
                break;
            }
            this.tab = tab;
        },

        composeSearch(input) {
            if (input.length < 1) { return []; }
            let self = this;
            let results = [];
            return axios.post('/api/direct/lookup', {
                q: input
            }).then(res => {
                return res.data;
            });
        },

        getTagResultValue(result) {
            // return '@' + result.name;
            return result.local ? '@' + result.name : result.name;
        },

        onTagSubmitLocation(result) {
            //this.$refs.autocomplete.value = '';
            this.composeLoading = true;
            window.location.href = '/account/direct/t/' + result.id;
            return;
        },

        messagePagination(tab, dir) {
            if(tab == 'inbox') {
                this.inboxPage = dir == 'prev' ? this.inboxPage - 1 : this.inboxPage + 1;
                axios.get('/api/direct/browse', {
                    params: {
                        a: 'inbox',
                        page: this.inboxPage
                    }
                })
                .then(res => {
                    self.loaded = true;
                    this.threads = res.data
                    this.messages.inbox = res.data;
                });
            }
            if(tab == 'sent') {
                this.sentPage = dir == 'prev' ? this.sentPage - 1 : this.sentPage + 1;
                axios.get('/api/direct/browse', {
                    params: {
                        a: 'sent',
                        page: this.sentPage
                    }
                })
                .then(res => {
                    self.loaded = true;
                    this.threads = res.data
                    this.messages.sent = res.data;
                });
            }
            if(tab == 'filtered') {
                this.filteredPage = dir == 'prev' ? this.filteredPage - 1 : this.filteredPage + 1;
                axios.get('/api/direct/browse', {
                    params: {
                        a: 'filtered',
                        page: this.filteredPage
                    }
                })
                .then(res => {
                    self.loaded = true;
                    this.threads = res.data
                    this.messages.filtered = res.data;
                });
            }
        }
    }
}
</script>