base_ui/components/dashboard/default/MyNotificationList.vue
2025-02-01 13:04:55 +03:30

2347 lines
65 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>