base_ui/components/charts/Tree.vue

806 lines
29 KiB
Vue
Raw Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div>
<v-chart
:key="treeCounter"
:option="option"
style="height: 90dvh; width: 90%"
ref="chart"
@mouseover="handleChartClick"
lazy
></v-chart>
<template v-if="showDiv">
<div
v-if="showButtons"
class="rounded shadow container-fluid p-2"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
:style="{
position: 'absolute',
top: position.top,
left: position.left,
backgroundColor: 'white',
border: '1px solid #dee2e6',
padding: '5px',
width: '15em',
}"
>
<div class="row me-auto tooltip-button">
<div class="col-9 d-flex border-bottom mb-1">
<button
v-tooltip="`افزودن فرزند`"
class="btn"
style="color: #dee2e6"
@click="onButtonClick('add')"
>
<svg class="icon icon-Component-133--1">
<use xlink:href="#icon-Component-133--1"></use>
</svg>
</button>
<button
v-tooltip="`ویرایش کردن`"
class="btn"
@click="onButtonClick('edit')"
>
<svg class="icon icon-Component-242--1">
<use xlink:href="#icon-Component-242--1"></use>
</svg>
</button>
<button
v-tooltip="`پاک کردن`"
class="btn"
@click="onButtonClick('delete')"
>
<svg class="icon icon-Component-295--1">
<use xlink:href="#icon-Component-295--1"></use>
</svg>
</button>
</div>
<div class="col-3 mb-1">
<button v-tooltip="`خارج شدن`" class="btn" @click="closeButtons">
<svg class="icon icon-Component-21--1">
<use xlink:href="#icon-Component-21--1"></use>
</svg>
</button>
</div>
</div>
<div class="row my-3">
<div v-if="buttonAction == 'add'" class="col w-90 px-3">
<form>
<div class="row align-items-center">
<div class="col-8 m-0">
<input
type="text"
class="form-control"
id="inlineFormInputName"
placeholder="کلمه جدید"
v-model="addText"
/>
</div>
<div class="col-2">
<button
class="btn accept-button"
@click.prevent="addNewChildren(addText)"
>
<svg class="icon icon-Component-233--1">
<use xlink:href="#icon-Component-233--1"></use>
</svg>
</button>
</div>
<div class="col-2">
<button class="btn reject-button" @click="buttonAction = ''">
<svg class="icon icon-Component-21--1">
<use xlink:href="#icon-Component-21--1"></use>
</svg>
</button>
</div>
</div>
</form>
</div>
<div v-else-if="buttonAction == 'edit'" class="col w-90 px-3">
<form>
<div class="row align-items-center">
<div class="col-8">
<input
type="text"
class="form-control"
id="inlineFormInputName"
:placeholder="tooltipText"
v-model="editText"
/>
</div>
<div class="col-2">
<button
class="btn accept-button"
@click.prevent="editNode(editText)"
>
<svg class="icon icon-Component-233--1">
<use xlink:href="#icon-Component-233--1"></use>
</svg>
</button>
</div>
<div class="col-2">
<button class="btn reject-button" @click="buttonAction = ''">
<svg class="icon icon-Component-21--1">
<use xlink:href="#icon-Component-21--1"></use>
</svg>
</button>
</div>
</div>
</form>
</div>
<div v-else class="col">
<p>{{ tooltipText }}</p>
</div>
</div>
</div>
</template>
</div>
</template>
<script>
import researchApi from "@apis/researchApi";
import HttpService from "@services/httpService";
import { mapActions, mapState } from "pinia";
2025-02-11 07:08:54 +00:00
import { useCommonStore } from "~/stores/commonStore";
2025-02-01 09:34:55 +00:00
//
import { use } from "echarts/core";
import { TreeChart } from "echarts/charts";
import { TooltipComponent, ToolboxComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
use([TooltipComponent, TreeChart, CanvasRenderer, ToolboxComponent]);
/**
* @vue-prop {Array} [dataTreeMap=] - آرایهای از دادههای نقشه درخت
*
* @vue-data {Number} treeCounter - شمارنده درخت
* @vue-data {Boolean} showButtons - وضعیت نمایش دکمهها
* @vue-data {Boolean} showDiv - وضعیت نمایش divدکمه ها
* @vue-data {String} buttonAction - اقدام دکمه
* @vue-data {String} addText - متن افزودن
* @vue-data {String} editText - متن ویرایش
* @vue-data {undefined|Object} httpService - سرویس HTTP
* @vue-data {Object} itemData - داده آیتم
* @vue-data {String} tooltipText - متن ابزارک راهنما
* @vue-data {Object} position - موقعیت ابزارک راهنما
* @vue-data {String} position.top - موقعیت عمودی ابزارک راهنما
* @vue-data {String} position.left - موقعیت افقی ابزارک راهنما
* @vue-data {Object} option - گزینههای پیکربندی نمودار
* @vue-data {Object} option.tooltip - تنظیمات ابزارک راهنما
* @vue-data {String} option.tooltip.trigger - نوع راهاندازی ابزارک راهنما
* @vue-data {String} option.tooltip.triggerOn - رویدادی که ابزارک راهنما بر اساس آن راهاندازی میشود
* @vue-data {Array} option.series - آرایهای از سریهای نمودار
* @vue-data {Object} option.series[0] - سری اول نمودار
* @vue-data {String} option.series[0].type - نوع سری (درخت)
* @vue-data {Number} option.series[0].id - شناسه سری
* @vue-data {String} option.series[0].name - نام سری
* @vue-data {Array} option.series[0].data - دادههای سری
* @vue-data {String} option.series[0].top - موقعیت بالای نمودار
* @vue-data {String} option.series[0].left - موقعیت چپ نمودار
* @vue-data {String} option.series[0].bottom - موقعیت پایین نمودار
* @vue-data {String} option.series[0].right - موقعیت راست نمودار
* @vue-data {String} option.series[0].while - عرض نمودار
* @vue-data {String} option.series[0].height - ارتفاع نمودار
* @vue-data {Number} option.series[0].zoom - میزان بزرگنمایی نمودار
* @vue-data {Number} option.series[0].symbolSize - اندازه نماد
* @vue-data {String} option.series[0].edgeForkPosition - موقعیت شاخههای لبه
* @vue-data {String} option.series[0].edgeShape - شکل لبه
* @vue-data {Number} option.series[0].initialTreeDepth - عمق اولیه درخت
* @vue-data {String} option.series[0].orient - جهت نمودار
* @vue-data {Object} option.series[0].lineStyle - سبک خط
* @vue-data {Number} option.series[0].lineStyle.width - عرض خط
* @vue-data {Object} option.series[0].label - برچسبها
* @vue-data {String} option.series[0].label.backgroundColor - رنگ پسزمینه برچسب
* @vue-data {Array} option.series[0].label.position - موقعیت برچسب
* @vue-data {Number} option.series[0].label.distance - فاصله برچسب
* @vue-data {String} option.series[0].label.verticalAlign - تراز عمودی برچسب
* @vue-data {String} option.series[0].label.align - تراز برچسب
* @vue-data {Number} option.series[0].label.borderWidth - عرض مرز برچسب
* @vue-data {Number} option.series[0].label.borderDashOffset - فاصله نقطهچین مرز برچسب
* @vue-data {Array} option.series[0].label.borderRadius - شعاع گوشههای مرز برچسب
* @vue-data {Array} option.series[0].label.padding - پدینگ برچسب
* @vue-data {Number} option.series[0].label.lineHeight - ارتفاع خط برچسب
* @vue-data {Object} option.series[0].leaves - برگها
* @vue-data {Object} option.series[0].leaves.label - برچسبهای برگ
* @vue-data {String} option.series[0].leaves.label.position - موقعیت برچسب برگ
* @vue-data {String} option.series[0].leaves.label.verticalAlign - تراز عمودی برچسب برگ
* @vue-data {String} option.series[0].leaves.label.align - تراز برچسب برگ
* @vue-data {Object} option.series[0].emphasis - تاکید
* @vue-data {String} option.series[0].emphasis.focus - تمرکز تاکید
* @vue-data {String} option.series[0].emphasis.blurScope - محدوده مات شدن تاکید
* @vue-data {Boolean} option.series[0].expandAndCollapse - وضعیت باز و بسته شدن
* @vue-data {Number} option.series[0].animationDuration - مدت زمان انیمیشن
* @vue-data {Number} option.series[0].animationDurationUpdate - مدت زمان بهروزرسانی انیمیشن
*/
export default {
props: {
dataTreeMap: {
default() {
return [];
},
type: Array,
},
},
data() {
return {
treeCounter: 1,
showButtons: false,
showDiv: false,
buttonAction: "",
addText: "",
editText: "",
httpService: undefined,
itemData: {},
tooltipText: "",
position: { top: "0px", left: "0px" },
option: {
tooltip: {
trigger: "item",
triggerOn: "mousemove",
},
toolbox: {
show: true,
itemSize: 15,
feature: {
myTool1: {
show: true,
title: " نمایش ",
icon: '<path d="M19.017 16.243c-1.431-0.009-2.588-1.166-2.597-2.596v-0.001c0.004-0.466 0.133-0.902 0.354-1.276l-0.006 0.012c-0.112-0.009-0.229-0.035-0.349-0.035-2.152 0-3.896 1.744-3.896 3.896s1.744 3.896 3.896 3.896c2.152 0 3.896-1.744 3.896-3.896v0c0-0.12-0.025-0.231-0.035-0.348-0.362 0.215-0.797 0.344-1.261 0.348h-0.001z"></path><path d="M16.42 7.152c-0.067-0.001-0.146-0.002-0.225-0.002-5.746 0-10.661 3.558-12.662 8.591l-0.032 0.092-0.133 0.411 0.133 0.411c2.035 5.125 6.951 8.683 12.697 8.683 0.079 0 0.157-0.001 0.236-0.002h-0.012c0.067 0.001 0.146 0.002 0.225 0.002 5.746 0 10.661-3.558 12.662-8.591l0.032-0.092 0.133-0.411-0.133-0.411c-2.035-5.125-6.951-8.683-12.697-8.683-0.079 0-0.157 0.001-0.236 0.002h0.012zM16.42 22.737c-0.107 0.004-0.234 0.006-0.36 0.006-4.417 0-8.218-2.642-9.907-6.432l-0.027-0.069c1.718-3.858 5.518-6.499 9.935-6.499 0.127 0 0.253 0.002 0.378 0.006l-0.018-0.001c0.107-0.004 0.234-0.006 0.36-0.006 4.417 0 8.218 2.642 9.907 6.432l0.027 0.069c-1.718 3.858-5.518 6.499-9.935 6.499-0.127 0-0.253-0.002-0.378-0.006h0.018z"></path>',
onclick: function () {
this.myToolClick("نمایش");
}.bind(this),
iconStyle: {
color: "",
},
},
myTool2: {
show: true,
title: " ویرایش ",
icon: '<path d="M9.333 25.856c-0.001 0-0.001 0-0.002 0-0.127 0-0.246-0.031-0.352-0.085l0.004 0.002-0.027 0.019-0.123-0.117c-0.024-0.021-0.046-0.041-0.066-0.064l-0-0-3.249-3.105 2.035-3.256 4.533 4.38-1.007 0.695h12.192c0.423 0 0.765 0.343 0.765 0.765s-0.343 0.765-0.765 0.765v0zM8.332 17.375l11.501-10.416c0.521-0.631 1.304-1.031 2.18-1.031 0.735 0 1.404 0.281 1.906 0.741l-0.002-0.002 1.333 1.5c0.385 0.41 0.621 0.963 0.621 1.571 0 0.714-0.325 1.351-0.836 1.773l-0.004 0.003-10.74 11.569z"></path>',
onclick: function () {
this.myToolClick("ویرایش");
}.bind(this),
iconStyle: {
color: "black",
},
},
},
},
series: [
{
type: "tree",
id: 0,
name: "tree1",
data: [],
top: "0%",
left: "40%",
bottom: "30%",
right: "5%",
while: "100%",
height: "100%",
zoom: 1,
symbolSize: 10,
// roam: true,
edgeForkPosition: "30%",
edgeShape: "curve",
// expandAndCollapse: true,
initialTreeDepth: 5,
orient: "RL",
// symbol: "none",
lineStyle: {
width: 2,
},
label: {
color: "#fff",
fontFamily: "sahel",
fontSize: 15,
align: "center",
position: "left",
verticalAlign: "middle",
borderRadius: 3,
padding: 6,
borderWidth: 2,
// shadowColor: "rgba(51, 41, 41, 1)",
// shadowBlur: 2.5,
// shadowOffsetX: 2,
// shadowOffsetY: 2,
width: 140,
height: 12,
backgroundColor: "#ee6666",
distance: 80,
formatter: function (params) {
const maxLength = 15;
const text =
params.name.length > maxLength
? params.name.substring(0, maxLength) + "..."
: params.name;
return text;
},
},
leaves: {
label: {
distance: 80,
color: "#fff",
fontFamily: "sahel",
fontSize: 15,
align: "center",
position: "left",
verticalAlign: "middle",
borderRadius: 3,
padding: 6,
borderWidth: 2,
// shadowColor: "rgba(51, 41, 41, 1)",
// shadowBlur: 2.5,
// shadowOffsetX: 2,
// shadowOffsetY: 2,
width: 140,
height: 12,
backgroundColor: "#fff",
formatter: function (params) {
const maxLength = 15;
const text =
params.name.length > maxLength
? params.name.substring(0, maxLength) + "..."
: params.name;
return text;
},
},
},
lineStyle: {
curveness: 0.6,
},
emphasis: {
focus: "relative",
blurScope: "coordinateSystem",
},
expandAndCollapse: true,
animationDuration: 550,
animationDurationUpdate: 750,
symbolOffset: [30, 0],
},
],
},
};
},
watch: {
dataTreeMap: {
handler(newData) {
this.option.series[0].data = newData;
this.treeCounter++;
},
deep: true,
immediate: true,
},
dataForTreeMapGetter(newValue) {
this.option.series[0].data = newValue;
this.treeCounter++;
},
},
beforeMount() {
this.httpService = new HttpService();
},
mounted() {
this.option.series[0].data = this.dataForTreeMapGetter;
this.option.toolbox.feature.myTool1.iconStyle.color = "black";
this.option.toolbox.feature.myTool2.iconStyle.color = "#fff";
},
computed: {
2025-02-11 07:08:54 +00:00
...mapState(useCommonStore, [
// "dataForTreeMapGetter",
2025-02-01 09:34:55 +00:00
"researchTermsGetter",
]),
},
methods: {
2025-02-11 07:08:54 +00:00
// ...mapActions(useResearchStore, ["dataForTreeMapSetter"]),
2025-02-01 09:34:55 +00:00
/**
*تغیرات مربوط به حالت نمایش و ویرایش در چارت
*/
myToolClick(item) {
if (item == "نمایش") {
this.showDiv = false;
this.option.toolbox.feature.myTool1.iconStyle.color = "black";
this.option.toolbox.feature.myTool2.iconStyle.color = "#fff";
} else {
this.showDiv = true;
this.option.toolbox.feature.myTool1.iconStyle.color = "#fff";
this.option.toolbox.feature.myTool2.iconStyle.color = "black";
}
},
/**
* نشان دادن دکمهها در هنگام وارد شدن ماوس
*/
onMouseEnter() {
this.showButtons = true;
},
/**
* پنهان کردن دکمهها در هنگام خارج شدن ماوس
*/
onMouseLeave() {
this.showButtons = false;
},
/**
* وقتی کاربر روی نقاط چارت کلیک میکند، این تابع وظیفه نمایش اطلاعات مربوط به آن نقطه را دارد.
* @param {Object} params - اطلاعات مربوط به کلیک شده روی چارت
*/
handleChartClick(params) {
const { offsetX, offsetY } = params.event;
// تنظیم موقعیت نمایش اطلاعات
this.position = { top: `${offsetY - 150}px`, left: `${offsetX}px` };
// نمایش متن توضیحات
this.tooltipText = params.name || "No data";
// ذخیره اطلاعات آیتم کلیک شده
this.itemData = params;
this.buttonAction = "";
this.addText = "";
this.editText = "";
// نمایش دکمه‌های مربوط به این آیتم
this.showButtons = true;
},
/**
* وقتی کاربر روی دکمههای اضافه کردن یا حذف کلیک میکند، این تابع عملکرد متناسب با دکمه انجام میدهد.
* @param {string} buttonName - نام دکمهای که کلیک شده است ('add' یا 'delete')
*/
onButtonClick(buttonName) {
this.buttonAction = buttonName;
// تعیین عملیات اضافه کردن یا حذف بر اساس دکمه انتخاب شده
if (buttonName == "add") this.fetchingExistingChildren();
else if (buttonName == "delete") this.removeNode();
// else if (buttonName == "edit") this.editNode();
},
/**
* این تابع دکمههای نمایش داده شده بر روی چارت را پنهان میکند.
*/
closeButtons() {
this.showButtons = false;
},
/**
* این تابع مسئول اضافه کردن آیتمهای جدید به چارت است.
* @param {string} item - عنوان آیتم جدید
*/
addNewChildren(item) {
let data = this.itemData.data;
// تهیه پارامترهای مورد نیاز برای ارسال درخواست
const payload = {
projectid: this.researchTermsGetter?.id,
parent: "",
listtype: 0,
title: item,
listid: "",
id: "",
};
// تنظیم مقادیر پارامترها بر اساس شرایط
if (data.pid === "Root") {
payload.id = undefined;
payload.parent = 0;
delete payload.listid;
} else {
payload.listid = data?.id;
payload.parent = data?.id;
delete payload.id;
}
// ارسال درخواست به سرور
let url = researchApi.subject.add;
this.httpService
.postRequest(url, payload)
.then((res) => {
// نمایش پیام موفقیت
this.mySwalToast({
title: "موفق",
html: " با موفقیت انجام شد ",
icon: "success",
});
// اضافه کردن آیتم‌های جدید به داده‌های مربوطه
res.data.forEach((element, index) => {
var node = {
item: element,
text: element.title,
name: element.title,
id: element.id,
pid: 0,
opened: false,
selected: false,
disabled: false,
loading: false,
children: [],
};
data.children.push(node);
// اضافه کردن آیتم به چارت
if (payload.parent === 0) {
this.option.series[0].data[0].children.push(node);
} else {
this.addChildToParent(
this.option.series[0].data[0],
payload.parent,
node
);
}
this.treeCounter++;
});
})
.catch((error) => {
// نمایش پیام خطا
console.error("Error adding new children:", error);
this.mySwalToast({
title: "خطا",
html: "مشکلی پیش آمد",
icon: "error",
});
})
.finally(() => {
this.buttonAction = "";
});
},
/**
* این تابع مسئول اضافه کردن یک آیتم فرزند به آیتم پدر میباشد.
* @param {Object} node - آیتم پدر
* @param {string} parentId - شناسه آیتم پدر
* @param {Object} newChild - آیتم فرزند جدید
* @returns {boolean} - مقدار منطقی True در صورت موفقیت آمیز بودن اضافه کردن، در غیر این صورت False
*/
addChildToParent(node, parentId, newChild) {
if (node.id === parentId) {
node.children.push(newChild);
return true;
}
if (node.children) {
for (let child of node.children) {
if (this.addChildToParent(child, parentId, newChild)) {
return true;
}
}
}
return false;
},
/**
* این تابع مسئول دریافت و نمایش آیتمهای موجود زیر یک آیتم پدر است.
*/
fetchingExistingChildren() {
let dataParent = this.itemData.data;
if (dataParent.children.length > 1) {
return;
}
try {
// دریافت لیست آیتم‌های زیر یک آیتم پدر از سرور
this.getListTree(dataParent.id).then((list) => {
// اضافه کردن هر آیتم به لیست فرزندان آیتم پدر
list.forEach((element, index) => {
const dataColor = dataParent.label.backgroundColor;
var node = {
item: element,
text: element.title,
name: element.title,
id: element.id,
pid: dataParent.id,
opened: false,
selected: false,
disabled: false,
loading: false,
children: [],
label: {
backgroundColor: dataColor,
},
itemStyle: {
color: dataColor,
},
};
dataParent.children.push(node);
// اضافه کردن آیتم به چارت
if (dataParent.id === 0) {
this.option.series[0].data[0].children.push(node);
} else {
this.addChildToParent(
this.option.series[0].data[0],
dataParent.id,
node
);
}
this.treeCounter++;
});
});
} catch (error) {
console.error("Error fetching children nodes:", error);
}
},
/**
* این تابع مسئول حذف یک آیتم از چارت میباشد.
*/
removeNode() {
let removeData = this.itemData.data;
if (removeData.pid === "Root") return;
this.mySwalConfirm({
title: "هشدار!!!",
html: `از حذف <b>${removeData.text}</b> اطمینان دارید؟ `,
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
this.getRemov(removeData);
this.closeButtons();
}
});
},
/**
* این تابع مسئول حذف یک آیتم از چارت میباشد.
* @param {Object} nodeToRemove - آیتمی که قرار است حذف شود
*/
removeNodeFromChart(nodeToRemove) {
// حذف آیتم از چارت
if (nodeToRemove.pid === 0) {
let index = this.option.series[0].data[0].children.findIndex(
(child) => child.item.id === nodeToRemove.item.id
);
if (index !== -1) {
this.option.series[0].data[0].children.splice(index, 1);
}
} else {
let parentData = this.getParentData(nodeToRemove);
if (parentData) {
let index = parentData.children.findIndex(
(child) => child.item.id === nodeToRemove.item.id
);
if (index !== -1) {
parentData.children.splice(index, 1);
}
}
}
this.treeCounter++; // افزایش شمارنده درخت
},
/**
* این تابع مسئول یافتن و بازگشت آیتم پدر مربوط به یک آیتم است.
* @param {Object} node - آیتم فرزند
* @returns {Object} - آیتم پدر
*/
getParentData(node) {
let parentData = null;
// جستجوی آیتم پدر با استفاده از شناسه آن
function findParent(nodeId, data) {
for (let i = 0; i < data.length; i++) {
if (data[i].id === nodeId) {
parentData = data[i];
break;
} else if (data[i].children && data[i].children.length) {
findParent(nodeId, data[i].children);
}
}
}
// فراخوانی تابع جستجوی آیتم پدر
findParent(node.pid, this.option.series[0].data[0].children);
return parentData;
},
/**
* این تابع مسئول دریافت لیست آیتمهای زیر یک آیتم پدر از سرور است.
* @param {string} parentId - شناسه آیتم پدر
* @returns {Promise} - لیست آیتمهای زیر آیتم پدر
*/
getListTree(parentId = 0) {
const payload = {
projectid: this.researchTermsGetter?.id,
parent: parentId,
sortby: "id",
offset: 0,
limit: 100,
listtype: 0,
};
let url = researchApi.subject.list;
// ارسال درخواست به سرور و بازگشت پاسخ به صورت Promise
return this.httpService.formDataRequest(url, payload).then((res) => {
return res.data;
});
},
/**
* این تابع مسئول حذف یک آیتم از چارت میباشد.
* @param {Object} item - آیتمی که قرار است حذف شود
*/
getRemov(item) {
const payload = {
subjectid: item.id,
projectid: this.researchTermsGetter?.id,
listid: item.id,
};
let url = researchApi.subject.delete;
this.httpService.postRequest(url, payload).then((res) => {
this.mySwalToast({
title: "موفق",
html: "با موفقیت حذف شد",
icon: "success",
});
// حذف آیتم از چارت
this.removeNodeFromChart(item);
});
},
/**
* این تابع مسئول ویرایش یک آیتم از چارت میباشد.
* @param {string} item - عنوان جدید آیتم
*/
editNode(item) {
let data = this.itemData.data;
const payload = {
subjectid: data.id,
projectid: this.researchTermsGetter?.id,
title: item,
};
let url = researchApi.subject.edit;
this.httpService
.formDataRequest(url, payload)
.then((res) => {
this.mySwalToast({
title: "موفق",
html: "تغییر نام با موفقیت انجام شد ",
icon: "success",
});
data.name = item;
data.text = item;
// پیدا کردن و به‌روز رسانی آیتم در چارت
const updateNodeText = (node, id, newText) => {
if (node.id === id) {
node.name = newText;
node.text = newText;
return true;
}
if (node.children) {
for (let child of node.children) {
if (updateNodeText(child, id, newText)) {
return true;
}
}
}
return false;
};
updateNodeText(this.option.series[0].data[0], data.id, item);
this.treeCounter++;
this.closeButtons();
})
.finally(() => {
this.buttonAction = "";
});
},
},
};
</script>
<style lang="scss">
.tooltip-button {
button {
color: #dee2e6 !important;
&:hover {
color: black !important;
}
}
}
.reject-button {
color: #dee2e6 !important;
&:hover {
color: rgb(231, 10, 10) !important;
}
}
.accept-button {
color: #dee2e6 !important;
&:hover {
color: rgb(37, 223, 12) !important;
}
}
</style>