base_ui/components/dashboard/default/MyNotificationList.vue

2347 lines
65 KiB
Vue
Raw Permalink Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div
class="menu-bar__content menu-bar-content home-list p-3"
:class="{ 'hidden-heder': !showMainpag }"
>
<!-- <div class="menu-bar__content menu-bar-content home-list p-3"
v-if="showMainpag"
> -->
<Breadcrumbs class="m-0" />
<div class="home-list__header pb-0">
<div class="flex-grow-1 search-main hidean-search" ref="search">
<button class="button-search open" @click="showSearchs()">
<span class="tavasi tavasi-Component-21--1"></span>
</button>
<form class="search-filter" role="search" @submit.prevent="sendQuery">
<div class="input-group mb-3">
<div class="input-group-append">
<button
class="input-group-text"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<!-- settings icon -->
<svg class="icon icon-settings">
<use xlink:href="#icon-settings"></use>
</svg>
</button>
<div class="dropdown-menu">
<button
@click.prevent="setSearchType('all')"
class="btn dropdown-item new-message"
:class="{ active: serachType == 'all' }"
type="button"
>
<svg class="icon icon-all">
<use xlink:href="#icon-all"></use>
</svg>
همه
</button>
<button
@click.prevent="setSearchType('personal')"
class="btn dropdown-item new-group"
:class="{ active: serachType == 'personal' }"
type="button"
>
<svg class="icon icon-personal">
<use xlink:href="#icon-personal"></use>
</svg>
شخصی
</button>
<button
@click.prevent="setSearchType('groups')"
class="btn dropdown-item new-group"
:class="{ active: serachType == 'groups' }"
type="button"
>
<svg class="icon icon-groups">
<use xlink:href="#icon-groups"></use>
</svg>
گروه ها
</button>
<button
@click.prevent="setSearchType('my-messages')"
class="btn dropdown-item new-group"
:class="{ active: serachType == 'my-messages' }"
type="button"
>
<svg class="icon icon-my-messages">
<use xlink:href="#icon-my-messages"></use>
</svg>
خوانده نشده ها
</button>
<button
@click.prevent="setSearchType('unread')"
class="btn dropdown-item new-group"
:class="{ active: serachType == 'unread' }"
type="button"
>
<svg class="icon icon-unread">
<use xlink:href="#icon-unread"></use>
</svg>
پیام های من
</button>
<button
@click.prevent="setSearchType('lobby')"
class="btn dropdown-item new-group"
:class="{ active: serachType == 'lobby' }"
type="button"
>
<svg class="icon icon-lobby">
<use xlink:href="#icon-lobby"></use>
</svg>
تالارها
</button>
</div>
</div>
<input
dir="rtl"
v-model.trim="searchText"
type="search"
required
class="form-control"
id="search-query"
placeholder="جستجو..."
name="search-query"
aria-label="جستجو در اسناد، عناوین و واژگان"
aria-describedby="basic-addon1"
size="50"
@keyup="sendQuery()"
@keydown="onKeyDown()"
/>
<div class="input-group-prepend">
<button
@click="clearSearchAndGetList"
type="button"
class="input-group-text"
id="basic-addon1"
>
<i v-if="searchText" class="tavasi tavasi-Component-294--1"></i>
</button>
</div>
</div>
</form>
</div>
<div class="navbar open">
<div class="navbar-grow">
<div
v-for="(item, index) in menu.chats"
:key="index"
class="hover-border"
>
<RouterLink
:to="{ name: item.link }"
class="has-sub-items gl-link"
>
<svg class="nav-icon-container" :class="'icon icon-' + item.icon">
<use :xlink:href="'#icon-' + item.icon"></use>
</svg>
</RouterLink>
</div>
<div class="hover-border1" @click="showSearchs()">
<span class="tavasi tavasi-Component-198--1"></span>
</div>
</div>
</div>
</div>
<div
class="home-list__content scroll-needed"
:class="{ loading: fetchingData }"
>
<div class="last-search h-100" id="last-search">
<div class="last-search-content h-100" @scroll="loadMore">
<div class="content">
<div v-if="$route.name == 'privates'">
<div
class="group-item"
v-for="(groupItem, index) in groups"
:key="index"
>
<div class="group-row enable-hover">
<div class="group-picture-container">
<context-menu
dataOffset="0,0"
style="position:static;"
:list="groups"
:clickedItem="groupItem"
:contextMenu="commonContextMenu"
:parentComponent="'groups-panel'"
@remove-item="removeItem(groups, groupItem, index)"
>
<!-- @generate-invite-post="openCreateForm('privates', groupItem)" -->
</context-menu>
<img
class="group-picture"
@error="handleImageSrcOnError($event, false)"
:src="getGroupAvatar(groupItem)"
:alt="groupItem.title"
/>
</div>
<button
type="button"
@click.prevent="showMessages(groups, groupItem, index)"
@click="showfilter()"
:title="groupItem.unread ?? 0"
class="btn group-content"
:class="{ active: groupItem.active ?? false }"
>
<div class="group-title-container">
<h4 class="group-title">
<!-- <span class="tavasi tavasi-personal"></span> -->
<svg class="icon icon-personal">
<use xlink:href="#icon-personal"></use>
</svg>
{{ groupItem.title }}
</h4>
<span class="group-time">
{{ convertUnixToPersianDateTime(groupItem.created_at) }}
</span>
</div>
<div class="group-description-container">
<p class="group-description">
{{ groupItem.desc }}
</p>
<span
v-if="groupItem?.seen_messages?.count > 0"
class="group-unread-indicator badge badge-info"
>
{{ groupItem?.seen_messages?.count ?? 0 }}
</span>
</div>
</button>
</div>
</div>
</div>
<div v-else-if="$route.name == 'groups'">
<div
class="group-item"
v-for="(groupItem, index) in groups"
:key="index"
>
<div
class="group-row "
:class="{ 'enable-hover': isGroupAdmin(groupItem) }"
>
<div class="group-picture-container">
<context-menu
v-if="isGroupAdmin(groupItem)"
dataOffset="0,0"
style="position:static;"
:list="groups"
:clickedItem="groupItem"
:contextMenu="commonContextMenu"
:parentComponent="'groups-panel'"
@remove-item="removeItem(groups, groupItem, index)"
@edit-item="editItem(groups, groupItem, index)"
@join-to-group="openGroupSearchForm('groups', groupItem)"
>
</context-menu>
<img
class="group-picture"
@error="handleImageSrcOnError($event, false)"
:src="getGroupAvatar(groupItem)"
:alt="groupItem.title"
/>
</div>
<button
type="button"
@click.prevent="showMessages(groups, groupItem, index)"
@click="showfilter()"
:title="groupItem.unread ?? 0"
class="btn group-content"
:class="{ active: groupItem.active ?? false }"
>
<div class="group-title-container">
<h4 class="group-title">
<!-- <span class="tavasi tavasi-groups"></span> -->
<svg class="icon icon-groups">
<use xlink:href="#icon-groups"></use>
</svg>
{{ groupItem.title }}
</h4>
<span class="group-time">
{{ convertUnixToPersianDateTime(groupItem.created_at) }}
</span>
</div>
<div class="group-description-container">
<p class="group-description">
{{ groupItem.desc }}
</p>
<span
v-if="groupItem?.seen_messages?.count > 0"
class="group-unread-indicator badge badge-info"
>
{{ groupItem?.seen_messages?.count ?? 0 }}
</span>
</div>
</button>
</div>
</div>
</div>
<div v-else-if="$route.name == 'unReads'">
<div
class="group-item unReads"
v-for="(groupItem, index) in groups"
:key="index"
>
<div class="group-row ">
<div class="group-picture-container">
<context-menu
dataOffset="0,0"
style="position:static;"
:list="groups"
:clickedItem="groupItem"
:contextMenu="commonContextMenu"
:parentComponent="'groups-panel'"
@remove-item="removeItem(groups, groupItem, index)"
@edit-item="editItem(groups, groupItem, index)"
>
</context-menu>
<img
class="group-picture"
@error="handleImageSrcOnError($event, false)"
:src="getGroupAvatar(groupItem)"
:alt="groupItem.title"
/>
</div>
<div
class="group-content p-2"
:class="{ active: groupItem.active ?? false }"
>
<div class="group-title-container">
<h4 class="group-title">
<!-- <span class="tavasi tavasi-personal"></span> -->
{{ groupItem.title }}
</h4>
<div class="unreads-box">
<!-- message info -->
<button
type="button"
@click.prevent="
showMessages(groups, groupItem, index)
"
:title="groupItem.unread ?? 0"
class="btn unread-button"
>
<!-- <span class="unread-message-label">
پیام ها :
</span> -->
<svg class="icon icon-Component-112--1">
<use xlink:href="#icon-Component-112--1"></use>
</svg>
{{ groupItem.seen_messages.count }}
</button>
<!-- replay info -->
<button
type="button"
@click.prevent="
showMessages(groups, groupItem, index)
"
:title="groupItem.unread ?? 0"
class="btn unread-button"
@click="showfilter()"
>
<!-- <span class="unread-message-label">
پاسخ ها :
</span> -->
<svg class="icon icon-reply">
<use xlink:href="#icon-reply"></use>
</svg>
{{ replayCount(groupItem.seen_replys) }}
</button>
</div>
<!-- <span class="group-time">
{{ convertUnixToPersianDateTime(groupItem.date_c) }}
</span> -->
</div>
<div class="group-description-container">
<p class="group-description">
{{ groupItem.last_message.text }}
</p>
<!-- <span class="group-unread-indicator badge badge-info">
{{ groupItem.seen.count }}
</span> -->
</div>
</div>
</div>
</div>
</div>
<div v-if="$route.name == 'lobbies'">
<div class="accordion" id="lobby-accordion">
<div
v-for="(lobby, key) in groups"
:key="key"
class="card border-0 group-item"
>
<div
class="card-header border-bottom-0 p-0"
:id="'heading' + key"
>
<button
type="button"
class="btn has-indicator group-row"
:title="lobby.title"
data-toggle="collapse"
:data-target="'#collapse' + key"
:aria-expanded="!collapseAll"
:class="[
{ collapsed: collapseAll },
{ ' enable-hover': isGroupAdmin(lobby) },
]"
:aria-controls="'collapse' + key"
>
<div class="group-picture-container">
<context-menu
v-if="isGroupAdmin(lobby)"
dataOffset="0,0"
style="position:static;"
:list="groups"
:clickedItem="lobby"
:contextMenu="commonContextMenu"
:parentComponent="'groups-panel'"
@remove-item="removeItem(groups, lobby, key)"
@edit-item="editItem(groups, lobby, key)"
>
</context-menu>
<img
class="group-picture"
@error="handleImageSrcOnError($event, false)"
:src="getGroupAvatar(lobby)"
:alt="lobby.title"
/>
</div>
<div class="group-content" @click="showfilter()">
<div class="group-title-container">
<h4 class="group-title">
<svg class="icon icon-lobby">
<use xlink:href="#icon-lobby"></use>
</svg>
<!-- <img
width="1em"
height="1em"
class=""
src="assets/common/img/lobby.svg"
alt="لابی"
/> -->
{{ lobby.title }}
</h4>
</div>
<div class="group-description-container">
<p class="group-description">
{{ lobby.desc }}
</p>
</div>
</div>
</button>
</div>
<div
:id="'collapse' + key"
class="collapse"
:class="{ show: !collapseAll }"
:aria-labelledby="'heading' + key"
data-parent="#lobby-accordion"
>
<div class="card-body p-0">
<ul class="list-group list-group-flush">
<li
:key="j"
v-for="(group, j) in lobby.sub_groups"
class="list-group-item p-0"
>
<button
type="button"
@click.prevent="
lobbyShowMessages(groups, key, group, j)
"
class="btn group-row"
:title="group.title"
:class="{ 'enable-hover': isGroupAdmin(group) }"
>
<div class="group-picture-container">
<context-menu
v-if="isGroupAdmin(group)"
dataOffset="0,0"
style="position:static;"
:list="groups"
:clickedItem="group"
:contextMenu="commonContextMenu"
:parentComponent="'groups-panel'"
@edit-item="editItem(groups, group, j)"
@remove-from-lobby="removeGroupFromLobby(group)"
>
</context-menu>
<img
class="group-picture"
@error="handleImageSrcOnError($event, false)"
:src="getGroupAvatar(group)"
:alt="group.title"
/>
</div>
<div
class="group-content"
:class="{ active: group.active ?? false }"
>
<div class="group-title-container">
<h4 class="group-title">
<img
width="1em"
height="1em"
class=""
:src="group.avatar"
:alt="group.title"
/>
{{ group.title }}
</h4>
<span class="group-time">
{{ group.created_at }}
</span>
</div>
<div class="group-description-container">
<p class="group-description">
{{
convertUnixToPersianDateTime(
group.created_at
)
}}
</p>
<span
v-if="group?.seen_messages?.count > 0"
class="group-unread-indicator badge badge-secondary"
>
{{ group?.seen_messages?.count ?? 0 }}
</span>
</div>
</div>
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- sidebar toggle button -->
<!-- <div class="d-md-none hide-list-panel">
<button
name="button"
type="button"
class="toggle-mobile-nav"
@click="$emit('hide-panel')"
>
<svg class="s12 icon-chevron-double-lg-right">
<use
href="assets/common/img/icons.svg#chevron-double-lg-right"
></use>
</svg>
<span class="collapse-text mr-2">بستن</span>
</button>
</div> -->
<!-- create new message button -->
<div class="btn-group dropup actions-button" data-offset="10,10">
<button
type="button"
class="btn"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<!-- plus icon -->
<span class="tavasi tavasi-Component-133--1 plus-icon"></span>
<!-- muliply icon -->
<span class="tavasi tavasi-Component-294--1 multiply-icon"></span>
</button>
<div class="dropdown-menu dropdown-menu-right">
<!-- Dropdown menu links -->
<button
@click.prevent="openUserSearchForm()"
class="btn dropdown-item new-message"
type="button"
>
<span class="tavasi tavasi-personal"></span>
پیام جدید
</button>
<button
@click.prevent="openCreateForm('groups')"
class="btn dropdown-item new-group"
type="button"
>
<span class="tavasi tavasi-groups"></span>
گروه جدید
</button>
<!-- <button
@click.prevent="openCreateForm('lobbies')"
class="btn dropdown-item new-lobby"
type="button"
>
<span class="tavasi tavasi-channel"></span>
تالار جدید
</button> -->
</div>
</div>
</div>
<div class="create-forms" v-if="showForm">
<div class="close-form mb-5">
<button
@click.prevent="closeCreateForm()"
type="button"
class="btn d-flex align-items-center pr-0"
>
<span class="tavasi tavasi-Component-71--1 ml-2"></span>
بازگشت
</button>
</div>
<!-- private chat -->
<div v-if="showUserSearchForm">
<div class="form-group">
<label for="users">انتخاب کاربر: </label>
<multiselect
id="users"
track-by="user_id"
placeholder="جستجوی..."
:show-labels="false"
:options="foundUsers"
:searchable="true"
:loading="isLoading"
:internal-search="false"
:clear-on-select="false"
:close-on-select="true"
:options-limit="300"
:limit="3"
:limit-text="limitText"
:max-height="600"
:customLabel="
(item) => {
return `${item.first_name} ${item.last_name}`;
}
"
@search-change="asyncFind"
@select="showUserPrivateMessages"
@close="isLoading = false"
>
<!-- <div slot="tag" slot-scope="{ option, remove }"
><span class="custom__tag"
><span>{{ option.name }}</span
><span class="custom__remove" @click="remove(option)"
></span
></span
></div
> -->
<!-- <div slot="clear" slot-scope="props">
<div
class="multiselect__clear"
v-if="selectedCountries.length"
@mousedown.prevent.stop="clearAll(props.search)"
></div> </div
><span slot="noResult"
>Oops! No elements found. Consider changing the search
query.</span
> -->
</multiselect>
</div>
</div>
<!-- finding group -->
<div v-if="showGroupSearchForm">
<div class="form-group">
<label for="add-member-group">جستجوی گروه: </label>
<multiselect
id="add-member-group"
track-by="id"
label="title"
placeholder="جستجوی..."
:options="foundGroups"
:searchable="true"
:loading="isLoading"
:internal-search="false"
:clear-on-select="false"
:close-on-select="true"
:options-limit="300"
:limit="3"
:limit-text="limitText"
:max-height="600"
@search-change="asyncFindGroup"
@select="addGroupToSelectedGroup"
@close="isLoading = false"
>
</multiselect>
</div>
</div>
<!-- group/lobby create/edit form -->
<form v-if="showNewGroupForm" @submit.prevent="createItem">
<div class="form-group">
<h6>
فرم ایجاد گروه
</h6>
</div>
<div v-if="formType == 'lobbies'" class="form-group">
<label for="exampleFormControlTextarea1">انتخاب گروه: </label>
<div class="d-flex align-items-center">
<multiselect
:allow-empty="true"
:searchable="true"
:close-on-select="true"
:show-labels="false"
label="title"
track-by="id"
placeholder="انتخاب تالار"
v-model="form.parent"
:options="groups"
:hide-selected="false"
:limit-text="
(count) => {
return `و ${count} تالار دیگر`;
}
"
:max-height="200"
>
</multiselect>
<div class="dropdown create-group-inner-form">
<button
type="button"
class="btn"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<!-- plus icon -->
<span class="tavasi tavasi-Component-133--1 plus-icon"></span>
<!-- muliply icon -->
<span
class="tavasi tavasi-Component-294--1 multiply-icon"
></span>
</button>
<div class="dropdown-menu ">
<div class="form-group">
<label for="form-title">عنوان: </label>
<input
type="text"
class="form-control"
id="form-title"
aria-describedby="title"
v-model.trim="form.title"
/>
</div>
<div class="form-group">
<label for="form-desc">توضیحات: </label>
<textarea
class="form-control"
id="form-desc"
rows="3"
v-model.trim="form.desc"
></textarea>
</div>
<div class="dropdown-divider"></div>
<div class="d-flex justify-content-between text-center">
<a
@click.prevent="createNewGroup"
class=" btn btn-primary "
href="#"
>ذخیره</a
>
<a
@click.prevent="createNewGroup"
class=" btn btn-danger "
href="#"
>انصراف</a
>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="exampleInputEmail1">عنوان: </label>
<input
type="text"
class="form-control"
id="exampleInputEmail1"
aria-describedby="title"
v-model.trim="form.title"
/>
<small id="emailHelp" class="form-text text-muted">
این متن فقط جنبه نمایشی دارد.
</small>
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">توضیحات: </label>
<textarea
class="form-control"
id="exampleFormControlTextarea1"
rows="3"
v-model.trim="form.desc"
></textarea>
</div>
<div class="form-group " v-if="form.id">
<div class="custom-checkbox-container position-static">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
id="enable-add-user-to-group"
v-model="showAddUserForm"
/>
<label
class="custom-control-label"
for="enable-add-user-to-group"
>
افزودن کاربر به گروه
</label>
</div>
</div>
<!-- private chat -->
<div v-if="showAddUserForm">
<div class="form-group">
<label for="users">جستجوی کاربر: </label>
<multiselect
id="users"
track-by="user_id"
placeholder="جستجوی..."
:show-labels="false"
:options="foundUsers"
:searchable="true"
:internal-search="false"
:clear-on-select="false"
:close-on-select="true"
:options-limit="300"
:limit="3"
:limit-text="limitText"
:max-height="600"
:customLabel="
(item) => {
return `${item.first_name} ${item.last_name}`;
}
"
@search-change="asyncFind"
@select="addUserToGroup"
>
</multiselect>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">
{{ form.id ? "بروزرسانی" : "ایجاد" }}
</button>
</form>
<!-- upload group/lobby avatar -->
<form v-if="showUploadAvatarForm" @submit.prevent="uploadAvatar">
<div class="form-group">
<h5>
بارگزاری آواتار
</h5>
</div>
<div class="form-group">
<div
class="image-uploader-container"
:class="{ 'hide-preview': hasImage }"
>
<image-uploader
ref="file-uploader"
:preview="true"
:debug="1"
:maxWidth="300"
:maxHeight="300"
:maxSize="2"
:quality="1"
:autoRotate="true"
outputFormat="file"
accept="image/*"
:className="['fileinput', { 'fileinput--loaded': hasImage }]"
:capture="false"
@input="setImage"
>
<label class="upload-label" for="fileInput" slot="upload-label">
<img
v-if="
form.avatar?.length &&
(getFileExtension(form.avatar) == 'png' ||
getFileExtension(form.avatar) == 'jpg' ||
getFileExtension(form.avatar) == 'jpeg')
"
:src="form.avatar"
class="img-fluid"
:alt="form.avatar"
/>
<span
v-else-if="form.avatar?.length"
class="tavasi "
:class="`tavasi-${getFileExtension(form.avatar)}-file`"
></span>
<!-- replace image src with incoming src -->
<span v-else class="tavasi tavasi-cloud-upload"></span>
</label>
</image-uploader>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
// import { dragDropMoveMixin } from "~/borhan/mixins/dragDropMoveMixin";
// import { searchMixin } from "~/borhan/mixins/searchMixin";
import ImageUploader from "vue-image-upload-resize";
import chatApi from "~/apis/chatApi";
import { mapActions, mapState } from "pinia";
import privatesContextMenu from "~/json/chat/json/privatesContextMenu.json";
import groupsContextMenu from "~/json/chat/json/groupsContextMenu.json";
import lobbiesContextMenu from "~/json/chat/json/lobbiesContextMenu.json";
import menu from "~/json/chat/json/menu.json";
import { useCommonStore } from "~/stores/commonStore";
import { useAuthStore } from "~/stores/authStore";
export default {
// mixins: [dragDropMoveMixin],
emits: ["list-changed", "list-item-changed"],
props: {
statusPagHedear: {
default: 1,
type: Number,
},
},
watch: {
$route: {
handler: function(to) {
this.isRedirectedFromOtherSystems = false;
this.getAll(to.name);
},
deep: true,
// immediate: true,
},
},
beforeMount() {
const headers = {
"app-id": import.meta.env.VITE_APP_ID,
lang: import.meta.env.VITE_LANG,
"app-version-code": import.meta.env.VITE_APP_VERSION,
};
this.httpService = new HttpService(
import.meta.env.VITE_MESSAGE_BASE_URL,
headers
);
this.authHttpService = new HttpService(import.meta.env.VITE_AUTH_BASE_URL);
if (this.$route.name == "privates")
this.commonContextMenu = privatesContextMenu;
if (this.$route.name == "groups")
this.commonContextMenu = groupsContextMenu;
if (this.$route.name == "lobbies")
this.commonContextMenu = lobbiesContextMenu;
if (this.$route.name == "unReads")
this.commonContextMenu = groupsContextMenu;
this.SET_LIST(undefined);
},
mounted() {
// check if redirected from other systems.
// or clicked on a copy link.
if (this.$route.query["group-id"]) {
this.groupId = this.$route.query["group-id"];
this.isRedirectedFromOtherSystems = true;
}
this.getAll(this.$route.name);
if (this.statusPagHedear == 1) {
}
},
data() {
return {
// #region mehdi
showMainpag: true,
menu: menu,
// #endregion
typingTimer: 0,
doneTypingInterval: 500,
searchText: "",
serachType: "all",
showAddUserForm: false,
busy: false,
foundGroups: [],
showUploadAvatarForm: false,
showGroupSearchForm: false,
groupsExpanded: false,
showNewGroupForm: false,
hasImage: false,
imageUrl: undefined,
uploading: false,
selectedUser: {},
foundUsers: [],
isLoading: false,
showUserSearchForm: false,
selectedGroup: undefined,
commonContextMenu: [],
fetchingData: false,
users: [],
prevSelectedItemIndex: 0,
prevParentSelectedItemIndex: 0,
convertGroupIntegerToString: {
groups: 1,
lobbies: 2,
privates: 3,
},
convertGroupStringToInteger: {
1: "groups",
2: "lobbies",
3: "privates",
},
showForm: false,
formType: 1,
form: {
id: undefined,
title: null,
desc: null,
type: 1,
message_state: 1,
members: [],
parent_id: undefined,
},
collapseAll: false,
groups: [],
showReplaceInput: true,
httpService: undefined,
authHttpService: undefined,
list: [],
pagination: {
pages: 0,
total: 0,
page: 1,
offset: 0, // page * per_page
limit: 50, //per_page
},
isRedirectedFromOtherSystems: false,
groupId: undefined,
messageId: undefined,
};
},
computed: {
...mapState(useCommonStore,["isSidebarCollapsed"]),
},
methods: {
...mapActions(useCommonStore, ["TOGGLE_PANEL", "checkPermissions"]),
...mapActions("list", ["SET_LIST"]),
sendQuery() {
// todo: show loading.
// todo: send query and show result.
// todo: hide loading.
clearTimeout(this.typingTimer);
this.typingTimer = setTimeout(() => {
this.getAll();
}, this.doneTypingInterval);
},
onKeyDown() {
clearTimeout(this.typingTimer);
},
setSearchType(type) {
this.serachType = type;
},
clearSearchAndGetList() {
this.searchText = null;
this.getAll();
},
async getAll(listType = "all") {
if (this.fetchingData) return;
this.fetchingData = true;
let url = chatApi[listType].list;
// let urlPrefix = chatApi.groups.list;
if (!(listType == "lobbies" || listType == "unReads"))
url += `${this.pagination.offset}/${this.pagination.limit}`;
// else if (listType == "lobbies") urlPrefix = chatApi.lobbies.list
// else if (listType == "privates") url += `${this.pagination.offset}/${this.pagination.limit}`;
// let url = urlPrefix + `${this.pagination.offset}/${this.pagination.limit}`
// const methodType = listType == "unReads" ? 'postRequest' : 'getRequest'
return await this.httpService
.getRequest(url)
.then((response) => {
this.groups = response.data;
this.users = response.users;
this.pagination = { ...this.pagination, ...response.pagination };
// when redirecting from other pages(jahat).
if (this.isRedirectedFromOtherSystems) {
this.groups.forEach((group) => {
if (group.id == this.groupId) {
group.active = true;
this.SET_LIST(group);
}
});
}
return response;
})
.catch((error) => {
})
.finally(() => {
this.fetchingData = false;
this.busy = false;
this.showMainpag = true;
});
},
setUser(list, responseUsers) {
list.forEach((listItem) => {
listItem.user = responseUsers.find(
(user) => user.user_id == listItem.user
);
});
},
createItem(group_id = undefined) {
if (this.fetchingData) return;
this.fetchingData = true;
let url = chatApi[this.$route.name].create;
// if (formType == "groups") urlPrefix =
// else if (formType == "lobbies") urlPrefix = chatApi.lobbies.create
// else if (formType == "privates") urlPrefix = chatApi.privates.create
// const payload = structuredClone(this.form);
this.form.members = JSON.stringify(this.form.members);
this.form.admins = undefined;
this.form.group_id = group_id;
this.httpService
.formDataRequest(url, this.form)
.then((res) => {
this.fetchingData = false;
// this.getAll(this.formType);
// this.form = res.data;
// this.mySwalToast({
// title: "",
// html: res.message,
// });
this.showNewGroupForm = false;
this.showUploadAvatarForm = true;
})
},
// remove group/remove lobby group
removeItem(groups, groupItem, index) {
this.mySwalConfirm({
title: "هشدار!!!",
html: `از حذف <b>${groupItem.title}</b> اطمینان دارید؟ `,
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
const payload = {
group_id: groupItem.id,
};
this.httpService
.postRequest(chatApi.groups.delete, payload)
.then((res) => {
// this.mySwalToast({
// html: res.message,
// icon: "success",
// });
this.getAll();
// groups.splice(index, 1);
});
}
});
},
editItem(groups, groupItem, index) {
this.form = structuredClone(groupItem);
this.markActive(groups, index);
this.openGroupCreateForm(this.convertGroupIntegerToString[this.formType]);
},
resetForm() {
this.form = {
id: undefined,
title: null,
desc: null,
type: 1,
message_state: 1,
members: [],
};
},
loadMore($event) {
// const listElm = document.querySelector("#last-search");
const listElm = $event.target;
const vm = this;
if (vm.busy) return;
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
this.busy = true;
vm.pagination.offset = vm.pagination.offset + vm.pagination.limit;
if (vm.pagination.total > vm.pagination.offset) {
setTimeout(() => {
vm.getListOnScroll();
}, 300);
} else {
vm.mySwalToast({
title: "کاربر محترم",
html: "دیگر رکوردی جهت بارگزاری وجود ندارد.",
icon: "info",
position: "bottom-start",
});
vm.busy = false;
}
} else vm.busy = false;
},
getListOnScroll() {
const listType = this.$route.name;
let url = chatApi[listType].list;
// let urlPrefix = chatApi.groups.list;
if (!(listType == "lobbies" || listType == "unReads"))
url += `${this.pagination.offset}/${this.pagination.limit}`;
// else if (listType == "lobbies") urlPrefix = chatApi.lobbies.list
// else if (listType == "privates") url += `${this.pagination.offset}/${this.pagination.limit}`;
// let url = urlPrefix + `${this.pagination.offset}/${this.pagination.limit}`
// const methodType = listType == "unReads" ? 'postRequest' : 'getRequest'
this.httpService
.getRequest(url)
.then((response) => {
this.pagination = { ...this.pagination, ...response.pagination };
this.groups = [...this.groups, ...response.data];
})
.finally(() => {
this.busy = false;
});
},
openUserSearchForm() {
this.showForm = true;
this.showUserSearchForm = true;
this.formType = "privates";
// this.loading = false;
// this.groupCreated = false;
},
openGroupSearchForm(formType, groupItem = undefined) {
this.showForm = true;
this.showGroupSearchForm = true;
this.formType = formType;
this.selectedGroup = groupItem;
},
openGroupCreateForm() {
this.showForm = true;
this.showNewGroupForm = true;
this.formType = "groups";
},
openCreateForm(formType, groupItem = undefined) {
// if (formType == 'privates')
// this.showUserSearchForm = true;
// else if (formType == 'groups')
this.showNewGroupForm = true;
this.selectedGroup = groupItem;
this.showForm = true;
this.formType = "groups";
this.loading = false;
},
closeCreateForm() {
this.showForm = false;
this.showNewGroupForm = false;
this.showGroupSearchForm = false;
this.showUserSearchForm = false;
this.showUploadAvatarForm = false;
this.loading = false;
this.resetForm();
this.$router
.push({
name: this.formType,
})
.catch(() => {});
},
closeCreateFormWithoutRedirect() {
this.showForm = false;
this.showNewGroupForm = false;
this.showGroupSearchForm = false;
this.showUserSearchForm = false;
this.showUploadAvatarForm = false;
this.loading = false;
},
resetPagination() {
this.pagination = {
pages: 0,
total: 0,
page: 1,
offset: 0, // page * per_page
limit: 50, //per_page
};
},
toggleSidebarMenu() {
this.$store.commit("TOGGLE_SIDEBAR_MENU");
},
markActive(groups, index) {
if (this.prevSelectedItemIndex != index) {
this.$set(groups[this.prevSelectedItemIndex], "active", false);
}
this.prevSelectedItemIndex = index;
this.$set(groups[index], "active", true);
},
showMessages(groups, groupItem, index) {
this.markActive(groups, index);
this.SET_LIST(groupItem);
history.pushState({}, document.title, this.$route.path);
this.isRedirectedFromOtherSystems = false;
this.$route.query["group-id"] = undefined;
this.$route.query["message-id"] = undefined;
this.$emit("update-messages");
},
// lobby,lobbyIndex.sub_groups_item, childIndex
lobbyShowMessages(lobby, parentIndex, groupItem, index) {
// اگر تالارثابت باشه و کاربر بر روی گروه های تالار کلیک کند.
if (
this.prevParentSelectedItemIndex == parentIndex &&
this.prevSelectedItemIndex != index
) {
this.$set(
lobby[this.prevParentSelectedItemIndex].sub_groups[
this.prevSelectedItemIndex
],
"active",
false
);
}
// کاربر بر روی تالار دیگری کلیک کرده است.
else if (this.prevParentSelectedItemIndex != parentIndex) {
this.$set(
lobby[this.prevParentSelectedItemIndex].sub_groups[
this.prevSelectedItemIndex
],
"active",
false
);
}
this.prevSelectedItemIndex = index;
this.prevParentSelectedItemIndex = parentIndex;
this.$set(lobby[parentIndex].sub_groups[index], "active", true);
this.SET_LIST(groupItem);
this.$emit("update-messages");
},
// after finding the user, on select user event, show the user's messages
showUserPrivateMessages(user) {
user.user = user.user_id;
// user.id = user.user_id;
user.title = userFullname(user);
user.desc = null;
this.SET_LIST(user);
this.groups.forEach((groupItem) => {
groupItem.active = false;
if (groupItem.user == user.id) groupItem.active = true;
});
this.closeCreateFormWithoutRedirect();
this.$emit("update-messages");
},
asyncFindGroup(query) {
if (this.isLoading) return;
this.isLoading = true;
if (query.trim().length) {
this.httpService
.getRequest("group/ve/search/1/" + query)
.then((response) => {
this.foundGroups = response.data ?? [];
})
.catch((err) => {
})
.finally(() => {
this.isLoading = false;
});
}
},
// add group to a group(making a lobby)
addGroupToSelectedGroup(comboSelectedGroup) {
if (this.fetchingData) return;
this.fetchingData = true;
let url = chatApi[this.$route.name].parent;
const payload = {
parent_id: comboSelectedGroup.id,
group_id: this.selectedGroup.id,
};
this.httpService
.formDataRequest(url, payload)
.then((res) => {
// this.mySwalToast({
// title: "",
// html: res.message,
// });
this.closeCreateForm();
})
.finally(() => {
this.fetchingData = false;
});
},
// remove from lobby
removeGroupFromLobby(group) {
this.mySwalConfirm({
title: "هشدار!!!",
html: ` حذف <b>${group.title}</b> ?`,
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
if (this.fetchingData) return;
this.fetchingData = true;
let url = chatApi[this.$route.name].delete;
const payload = {
group_id: group.id,
parent_id: 0,
};
this.httpService
.formDataRequest(url, payload)
.then((res) => {
this.fetchingData = false;
// this.mySwalToast({
// html: res.message,
// });
this.getAll("lobbies");
})
}
});
},
replayCount(replays) {
let sum = 0;
replays.forEach((item) => {
sum += item.count;
});
return sum;
},
limitText(count) {
return `و ${count} کاربر دیگر`;
},
asyncFind(query) {
if (this.isLoading) return;
this.isLoading = true;
if (query.trim().length) {
this.authHttpService
.postRequest("user/suggestion", { query })
.then((response) => {
this.isLoading = false;
this.foundUsers = response.data ?? [];
})
.catch((err) => {
})
}
},
isGroupAdmin(comment) {
const isAdmin =
comment.admins.findIndex((user) => user == this.currentUser.user_id) >
-1;
return isAdmin;
},
getFileExtension(filename) {
const validtypes = [
"xlsx",
"xls",
"doc",
"docx",
"ppt",
"pptx",
"txt",
"pdf",
"jpg",
"png",
"jpeg",
];
const fileExtension = filename?.split(".").pop();
return validtypes.includes(fileExtension) ? fileExtension : "other";
},
setImage(file) {
this.hasImage = true;
this.imageUrl = file;
this.form.avatar = file.name;
this.saveFile(file);
},
saveFile() {
if (this.uploading) return;
this.uploading = true;
let url = chatApi.groups.updateAvatar + this.form.id;
const formData = new FormData();
formData.append("file", this.$refs["file-uploader"].currentFile);
this.httpService
.postRequest(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
// this.mySwalToast({
// title: res.message,
// html: "",
// });
this.closeCreateForm();
// this.getAll();
})
.catch((err) => {
})
.finally(() => {
this.uploading = false;
});
},
addUserToGroup(selectedUser) {
if (this.fetchingData) return;
this.fetchingData = true;
let url = chatApi.groups.addMember;
const payload = {
group_id: this.form.id,
members: [selectedUser.id],
};
this.httpService
.postRequest(url, payload)
.then((res) => {
// this.mySwalToast({
// title: "",
// html: res.message,
// });
// this.closeCreateForm();
// this.getAll();
})
.catch((err) => {
})
.finally(() => {
this.isLoading = false;
this.fetchingData = false;
});
},
// #region mehdi
showfilter() {
this.showMainpag = !this.showMainpag;
},
showSearchs() {
this.showSearch = false;
this.$refs.search.classList.toggle("hidean-search");
},
// #endregion
},
};
</script>
<style scoped lang="scss">
@import "../../../../assets/common/scss/mixin.scss";
.group-item {
.group-row {
display: flex;
align-items: center;
width: 100%;
max-width: 100%;
margin-bottom: 0.3em;
&.enable-hover:hover {
.group-picture-container {
.context-menu-dropdown {
display: flex;
}
.group-picture {
display: none;
}
}
.group-content {
background-color: #f0f0f0;
}
}
.group-picture-container {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
// margin-left: 0.5em;
border: 1px solid #ccc;
width: 2.3em;
height: 2.3em;
position: relative;
background-color: #fff;
.context-menu-dropdown {
display: none;
}
.group-picture {
object-fit: cover;
object-position: center;
overflow: hidden;
border-radius: 50%;
width: 100%;
height: 100%;
}
}
.group-content {
flex: 1;
border-radius: 0;
position: relative;
padding: 0.3em;
&:active,
&.active {
background-color: #d8f8fd;
}
.group-title-container {
display: flex;
align-items: center;
justify-content: space-between;
.group-title {
// display: flex;
flex: 1;
text-align: right;
// align-items: center;
// font-size: 0.7rem;
font-size: 0.8rem;
margin-bottom: 0.3em;
// font-family: "sahel-bold";
font-family: "sahel-semi-bold";
color: #444;
@include textOverflow(13em);
.tavasi {
font-size: 0.8rem;
margin-left: 0.3em;
}
}
.group-time {
font-size: 0.7rem;
font-family: "sahel-light";
}
.unreads-box {
display: flex;
align-items: center;
.btn {
padding: 0;
margin: 0;
margin-right: 0.5em;
color: #888;
svg {
font-size: 0.7rem;
}
}
}
}
.group-description-container {
display: flex;
align-items: center;
justify-content: space-between;
.group-unread-indicator {
font-size: 0.7rem;
background-color: #00b6e3;
font-family: "sahel-light";
display: flex;
justify-content: center;
align-items: center;
padding-top: 0.4em;
}
.group-description {
color: #6f6f6f;
font-size: 0.8em;
margin: 0;
flex: 1;
text-align: right;
@include textOverflow(15em);
}
}
.unread-button {
.unread-message-label {
font-size: 0.7rem;
color: #6f6f6f;
margin-left: 0.3em;
line-height: 1;
}
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 0.2em;
font-size: 0.9rem;
line-height: 1.2;
}
}
}
}
#lobby-accordion {
& > .card {
overflow: visible;
}
.list-group-item {
border-radius: 0;
&:not(:last-child) {
border-bottom: 1px dashed #ddd;
}
// &:last-child {
// .group-content {
// &::before{
// content:none;
// }
// }
// }
}
.card-header {
.group-row:hover {
.group-content {
background-color: transparent;
}
}
}
.card-body {
.group-row {
&:hover {
}
&:active,
&.active {
}
.group-picture-container {
.group-picture {
// width: 3em;
// height: 3em;
}
}
.group-content {
.group-title-container {
.group-title {
font-size: 0.8rem;
.tavasi {
font-size: 0.7rem;
// margin-left: 0.3em;
}
}
.group-time {
font-size: 0.7rem;
}
}
.group-description-container {
.group-unread-indicator {
font-size: 0.7rem;
}
.group-description {
font-size: 0.7rem;
}
}
}
}
}
}
.menu-bar__content {
position: static;
flex: 1 1 100%;
max-width: 25em;
max-width: 20em;
width: auto;
min-width: 20em;
&.show-list-panel {
right: 0 !important;
}
}
.home-list__content {
/*max-height: calc(100vh - 12em);*/
height: calc(100vh - 8.5em);
position: relative;
overflow-x: hidden;
padding-left: 0.3em;
&.loading {
//background-image: url('./img/item-loading.svg');
background-repeat: repeat-y;
background-position: top right;
background-size: 12em;
&::before {
content: "";
clear: both;
position: absolute;
right: 0;
width: 0.5em;
height: 100%;
background-color: #fff;
animation-name: example;
animation-duration: 2s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
}
&:hover .actions-button {
opacity: 1;
visibility: visible;
transition: all 0.2s;
}
}
.actions-button {
position: absolute;
bottom: 1em;
left: 1em;
z-index: 1;
width: 2.3em;
height: 2.3em;
background-color: #00b6e3;
border-radius: 50%;
opacity: 0;
visibility: hidden;
transition: all 0.2s;
& > .btn {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
.plus-icon {
display: inline;
}
.multiply-icon {
display: none;
}
&.show {
.plus-icon {
display: none;
}
.multiply-icon {
display: inline;
}
}
.btn[data-toggle="dropdown"] {
.tavasi::before {
color: #fff;
}
}
.dropdown-menu.show {
// top: -10px !important;
// padding-top: 1.5em;
// padding-bottom: 1.5em;
}
.dropdown-item {
text-align: right;
font-family: "sahel-semi-bold";
display: flex;
align-items: center;
margin-bottom: 0.7em;
font-size: 0.8rem;
color: #666;
.tavasi {
margin-left: 0.5em;
}
}
}
.search-filter {
.input-group-text {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
// border: 1px solid #ddd;
}
.input-group-append {
.input-group-text {
border-top-right-radius: 0.5em;
border-bottom-right-radius: 0.5em;
background-color: transparent;
}
}
.input-group-prepend {
.input-group-text {
background-color: transparent;
border-top-left-radius: 0.5em;
border-bottom-left-radius: 0.5em;
}
}
.form-control {
border-left: 0;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
&::-webkit-search-decoration,
&::-webkit-search-cancel-button,
&::-webkit-search-results-button,
&::-webkit-search-results-decoration {
-webkit-appearance: none;
}
}
.dropdown-item {
text-align: right;
font-family: "sahel-semi-bold";
display: flex;
align-items: center;
margin-bottom: 0.7em;
font-size: 0.8rem;
.icon {
margin-left: 0.2em;
}
}
}
.create-forms {
position: fixed;
right: 3.5em;
top: 0;
bottom: 0;
min-width: 20em;
background-color: #fff;
width: 0;
width: 100%;
max-width: 20em;
z-index: 2;
overflow: hidden;
padding: 1em 2em;
.form-control,
label,
.btn {
font-size: 0.8rem;
}
}
.create-group-inner-form {
& > .btn {
margin-right: 0.2em;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
width: 2em;
height: 2em;
background-color: #00b6e3;
border-radius: 50%;
}
.plus-icon {
display: inline;
}
.multiply-icon {
display: none;
}
&.show {
.plus-icon {
display: none;
}
.multiply-icon {
display: inline;
}
}
.btn[data-toggle="dropdown"] {
.tavasi::before {
color: #fff;
}
}
.dropdown-menu.show {
width: 17em;
text-align: right;
padding: 1.5em 1em;
}
.dropdown-item {
text-align: right;
display: flex;
align-items: center;
margin-bottom: 0.7em;
color: #666;
.tavasi {
margin-left: 0.5em;
}
}
}
</style>
<style lang="scss">
.picture-input input[type="file"],
#fileInput {
display: none !important;
}
.image-uploader-container {
position: relative;
// border: 2px dashed #eee;
padding: 0.2em;
&.hide-preview {
.upload-label {
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
width: auto !important;
overflow: hidden;
.tavasi,
img {
visibility: hidden;
}
}
}
.upload-label {
.tavasi {
font-size: 4rem;
}
&:hover {
cursor: pointer;
}
}
.img-preview {
width: 300px;
max-width: 100%;
height: auto;
max-height: 200px;
object-fit: contain;
}
}
</style>
<!-- start: mehdi -->
<style scoped lang="scss">
.input-group {
display: flex;
flex-direction: row;
justify-content: space-evenly;
flex-wrap: nowrap;
}
.nav-icon-container {
font-size: 0.875rem;
color: #a0acb8;
}
//mehdi
@media (min-width: 992px) {
.open {
display: none;
}
.home-list__header {
padding-top: 1em;
}
}
@media only screen and (min-width: 768px) and (max-width: 991.98px) {
.hidden-heder {
display: none;
}
.menu-bar__content {
position: fixed;
top: 0rem !important;
right: 3rem !important;
right: 2rem;
background-color: #fff;
z-index: 9;
}
.open {
display: none;
}
}
@media only screen and (min-width: 576px) and (max-width: 766.98px) {
.hidden-heder {
display: none;
}
.menu-bar__content {
position: fixed;
right: 0rem !important;
background-color: #fff;
z-index: 9;
// max-width: 25em;
// max-width: 20em;
width: auto;
min-width: 100% !important;
}
.navbar {
width: 100%;
height: 4.1rem;
position: relative;
left: 0.3rem;
display: flex;
align-items: center;
//background-color: red;
.navbar-grow {
width: 100%;
display: flex;
justify-content: space-evenly;
div {
margin-left: 1.2rem;
}
}
}
.hover-border {
position: relative;
border: 2px solid transparent;
border-radius: 5px;
transition: transform 0.3s ease;
}
.hover-border:hover {
transform: translateY(-5px);
.nav-icon-container {
color: black !important;
}
}
.search-main {
display: flex;
flex-direction: row-reverse;
position: absolute;
z-index: 999;
top: 24px;
background-color: #fff;
width: 100%;
justify-content: center;
// background-color: red;
.button-search {
position: relative;
width: 35px;
height: 31px;
margin-right: 5px;
margin-left: 5px;
margin-top: 2px;
border: none;
background-color: #fff;
&:hover {
border-radius: 5px;
border: 1px solid #a0acb8;
background-color: #a0acb8;
color: #fff;
}
span {
position: absolute;
top: 3px;
right: 0px;
}
}
}
.hidean-search {
display: none !important;
}
.hover-border1 {
position: relative;
top: 7px;
}
}
@media (max-width: 575.98px) {
.hidden-heder {
display: none;
}
.menu-bar__content {
position: fixed;
right: 0rem !important;
background-color: #fff;
z-index: 9;
// max-width: 25em;
// max-width: 20em;
width: auto;
min-width: 100% !important;
}
.navbar {
width: 100%;
height: 4.1rem;
position: relative;
left: 0.3rem;
display: flex;
align-items: center;
//background-color: red;
.navbar-grow {
width: 100%;
display: flex;
justify-content: space-between;
div {
margin-left: 1.2rem;
}
}
}
.hover-border {
position: relative;
border: 2px solid transparent;
border-radius: 5px;
}
.hover-border:hover {
.nav-icon-container {
color: black !important;
}
}
.hover-border1 {
position: relative;
top: 6px;
right: 6px;
}
.search-main {
display: flex;
flex-direction: row-reverse;
position: absolute;
z-index: 999;
top: 24px;
background-color: #fff;
// background-color: red;
.button-search {
position: relative;
width: 35px;
height: 31px;
margin-right: 5px;
margin-left: 5px;
margin-top: 2px;
border: none;
background-color: #fff;
&:hover {
border-radius: 5px;
border: 1px solid #a0acb8;
background-color: #a0acb8;
color: #fff;
}
span {
position: absolute;
top: 3px;
right: 0px;
}
}
}
.hidean-search {
display: none !important;
}
.home-list__content {
top: -14px;
}
.navbar {
top: -14px;
}
}
//mehdi
</style>