348 lines
9.9 KiB
Vue
348 lines
9.9 KiB
Vue
<template>
|
|
<div
|
|
ref="claimMessage"
|
|
:class="`${!isSystemMessage ? isAuthenticableUser ? 'auth-user-message' : 'other-message' : 'automatic-message'} d-flex flex-column justify-content-center mb-2`"
|
|
>
|
|
<div class="message-wrapper d-flex align-items-center w-100">
|
|
<!-- BTN VALID UPDATING -->
|
|
<div v-if="loading">
|
|
<div
|
|
class="spinner-border spinner-border-sm me-2"
|
|
role="status"
|
|
>
|
|
<span class="visually-hidden">{{ trans.methods.__('Chargement...') }}</span>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="!loading && isAuthenticableUser"
|
|
class="d-flex flex-column justify-content-center align-items-center me-1"
|
|
>
|
|
<!-- SET UPDATING MODE -->
|
|
<button
|
|
v-if="!updating"
|
|
class="btn btn-sm btn-outline-primary border-0 d-flex align-items-center justify-content-center"
|
|
data-bs-tooltip="tooltip"
|
|
type="button"
|
|
:title="trans.methods.__('Modifier votre message')"
|
|
@click="setUpdatingMode(true)"
|
|
:disabled="loading"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-pencil" />
|
|
</button>
|
|
<button
|
|
v-if="updating"
|
|
class="btn btn-sm btn-success border-0 d-flex align-items-center justify-content-center mb-1"
|
|
data-bs-tooltip="tooltip"
|
|
type="button"
|
|
:title="trans.methods.__('Valider la modification')"
|
|
@click="updateMessage"
|
|
:disabled="loading"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-check" />
|
|
</button>
|
|
<!-- BTN CANCEL UPDATING -->
|
|
<button
|
|
v-if="updating"
|
|
class="btn btn-sm btn-danger border-0 d-flex align-items-center justify-content-center"
|
|
data-bs-tooltip="tooltip"
|
|
type="button"
|
|
:title="trans.methods.__('Annuler la modification')"
|
|
@click="setUpdatingMode(false)"
|
|
:disabled="loading"
|
|
>
|
|
<FontAwesomeIcon icon="fa-solid fa-xmark" />
|
|
</button>
|
|
</div>
|
|
<!-- MESSAGE CONTENT -->
|
|
<div :class="`message-content text-${isAuthenticableUser ? 'white' : 'dark'} text-break shadow-sm rounded-2 p-2 ${updating ? 'w-100' : 'w-fit'}`">
|
|
<template v-if="!updating">
|
|
<p
|
|
class="m-0"
|
|
:class="{ 'px-4': isSystemMessage }"
|
|
v-html="claimMessageModelContent"
|
|
/>
|
|
</template>
|
|
<textarea
|
|
v-if="updating && !isSystemMessage"
|
|
ref="messageTextarea"
|
|
class="form-control"
|
|
:class="{'is-invalid': errors.methods.parseValidationInput('content', allErrors)}"
|
|
v-model="claimMessageModelContent"
|
|
:disabled="loading"
|
|
/>
|
|
<small
|
|
v-if="Object.keys(allErrors).length"
|
|
class="text-danger bg-white rounded-2 px-1 m-0"
|
|
>
|
|
{{ errors.methods.parseValidationInput('content', allErrors) }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<small class="message-details d-flex flex-column flex-lg-row text-secondary fst-italic">
|
|
<span v-if="isSystemMessage">
|
|
{{ trans.methods.__('Message système à :date', {
|
|
date: getFormatedTime(String(claimMessageModel.created_at)),
|
|
}) }}
|
|
</span>
|
|
<span v-else>
|
|
{{ trans.methods.__(':user à :date', {
|
|
user: claimMessageModel.user ? `${claimMessageModel.user?.first_name} ${claimMessageModel.user?.last_name}` : trans.methods.__('Utilisateur supprimé'),
|
|
date: getFormatedTime(String(claimMessageModel.created_at)),
|
|
}) }}
|
|
</span>
|
|
<span
|
|
v-if="showDates || claimMessageModel.created_at !== claimMessageModel.updated_at"
|
|
class="ms-1"
|
|
>
|
|
{{ trans.methods.__('- Mis à jour le :date', {
|
|
date: getFormatedDate(String(showDates ? new Date() : claimMessageModel.updated_at)),
|
|
}) }}
|
|
</span>
|
|
</small>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, onMounted, ref, nextTick, useAttrs } from "vue";
|
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
|
import type { PropType } from "vue";
|
|
import errors from "./../../modules/errors";
|
|
import route from "./../../modules/route";
|
|
import trans from "./../../modules/trans";
|
|
import { Tooltips } from "./../../modules/tooltips";
|
|
|
|
defineOptions({
|
|
name: "ClaimMessageComponent"
|
|
});
|
|
|
|
// * ATTRIBUTES
|
|
const attrs = useAttrs();
|
|
|
|
// * EMITS
|
|
const emits = defineEmits<{
|
|
(e: "setLoadingMessage", value: boolean): void;
|
|
}>();
|
|
|
|
// * PROPS
|
|
const props = defineProps({
|
|
authUserId: {
|
|
type: Number,
|
|
default: Math.pow(10, 16) / Math.random(),
|
|
},
|
|
claimMessageModel: {
|
|
type: Object as PropType<LaravelModel & LaravelModelUserRelation>,
|
|
default: () => { return []; },
|
|
},
|
|
loading: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
updating: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
showDates: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
allErrors: {
|
|
type: Object as PropType<LaravelValidationErrors>,
|
|
default: () => { return {}; },
|
|
},
|
|
});
|
|
|
|
// * REFS
|
|
const claimMessage = ref<HTMLDivElement|null>(null);
|
|
const messageTextarea = ref<HTMLElement|null>(null);
|
|
|
|
// * DATA
|
|
const authUserId = ref<number>(props.authUserId);
|
|
const claimMessageModel = ref<LaravelModel & LaravelModelUserRelation>(props.claimMessageModel);
|
|
const claimMessageModelContent = ref<string>(String(props.claimMessageModel.content ?? ""));
|
|
const loading = ref<boolean>(props.loading);
|
|
const updating = ref<boolean>(props.updating);
|
|
const showDates = ref<boolean>(props.showDates);
|
|
const tooltips = ref<Tooltips|null>(null);
|
|
const allErrors = ref<LaravelValidationErrors>(props.allErrors);
|
|
const MessageType = {
|
|
auto: 1,
|
|
human: 2,
|
|
};
|
|
|
|
// * COMPUTED
|
|
const isUsedWithProps = computed<boolean>(() => attrs.json === undefined);
|
|
const isAuthenticableUser = computed<boolean>(() => claimMessageModel.value.user !== null && claimMessageModel.value.user.id === authUserId.value);
|
|
const isSystemMessage = computed<boolean>(() => claimMessageModel.value.type === MessageType.auto);
|
|
|
|
// * LIFECYCLE
|
|
onMounted((): void => {
|
|
const json = String(attrs.json ?? "{}"),
|
|
data = JSON.parse(json);
|
|
if (!isUsedWithProps.value) {
|
|
authUserId.value = data.authUserId;
|
|
claimMessageModel.value = data.claimMessageModel;
|
|
claimMessageModelContent.value = String(claimMessageModel.value.content ?? "");
|
|
loading.value = data.loading;
|
|
updating.value = data.updating;
|
|
allErrors.value = data.allErrors;
|
|
}
|
|
initTooltips();
|
|
});
|
|
|
|
// * METHODS
|
|
|
|
/**
|
|
* Update the message.
|
|
* @return void
|
|
*/
|
|
function updateMessage(): void {
|
|
// Check if there is no changes.
|
|
if (claimMessageModelContent.value.trim() === claimMessageModel.value.content) {
|
|
claimMessageModelContent.value = claimMessageModelContent.value.trim();
|
|
updating.value = false;
|
|
nextTick(() => {
|
|
tooltips.value?.closeBootstrapTooltip();
|
|
initTooltips();
|
|
});
|
|
return;
|
|
}
|
|
loading.value = true;
|
|
allErrors.value = {};
|
|
emits("setLoadingMessage", loading.value);
|
|
window.axios
|
|
.patch(route.methods.getRoute("bo.claim_messages.update", {
|
|
CLAIMMESSAGEID: String(claimMessageModel.value.id),
|
|
}), {
|
|
claim_message_id: claimMessageModel.value.id,
|
|
content: claimMessageModelContent.value,
|
|
})
|
|
.then((response) => {
|
|
claimMessageModel.value.content = response.data.content;
|
|
claimMessageModelContent.value = response.data.content;
|
|
updating.value = false;
|
|
loading.value = false;
|
|
showDates.value = true;
|
|
nextTick(() => {
|
|
messageTextarea.value?.focus();
|
|
tooltips.value?.closeBootstrapTooltip();
|
|
initTooltips();
|
|
});
|
|
emits("setLoadingMessage", loading.value);
|
|
})
|
|
.catch((e) => {
|
|
loading.value = false;
|
|
emits("setLoadingMessage", loading.value);
|
|
allErrors.value = e.response?.data?.errors ?? {};
|
|
errors.methods.ajaxErrorHandler(e);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set the updating mode.
|
|
* @return void
|
|
*/
|
|
function setUpdatingMode(value: boolean): void {
|
|
updating.value = value;
|
|
claimMessageModelContent.value = String(claimMessageModel.value.content);
|
|
if (!updating.value) {
|
|
allErrors.value = {};
|
|
}
|
|
nextTick(() => {
|
|
messageTextarea.value?.focus();
|
|
tooltips.value?.closeBootstrapTooltip();
|
|
initTooltips();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Return a formated date.
|
|
* @return string
|
|
*/
|
|
function getFormatedDate(unformatedDate: string): string {
|
|
const date = new Date(unformatedDate);
|
|
|
|
return new Intl.DateTimeFormat("fr-FR", {
|
|
weekday: "long",
|
|
day: "numeric",
|
|
month: "long",
|
|
year: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
}).format(date);
|
|
}
|
|
|
|
/**
|
|
* Return a formated date.
|
|
* @return string
|
|
*/
|
|
function getFormatedTime(unformatedTime: string): string {
|
|
const date = new Date(unformatedTime);
|
|
|
|
return new Intl.DateTimeFormat("fr-FR", {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
}).format(date);
|
|
}
|
|
|
|
/** Initialise all tooltips in the component. */
|
|
function initTooltips(): void {
|
|
setTimeout(() => {
|
|
tooltips.value = Tooltips.make({
|
|
type: "dom",
|
|
elements: claimMessage.value!.querySelectorAll("[data-bs-tooltip=\"tooltip\"]")
|
|
});
|
|
}, 500);
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.message-content {
|
|
max-width: 70%;
|
|
p {
|
|
white-space: pre-line;
|
|
}
|
|
}
|
|
.other-message {
|
|
align-items: flex-start;
|
|
.message-wrapper, {
|
|
justify-content: flex-start;
|
|
}
|
|
.message-details {
|
|
align-items: flex-start;
|
|
}
|
|
.message-content {
|
|
background-color: #e6e6e6;
|
|
border-bottom-left-radius: 0 !important;
|
|
}
|
|
}
|
|
.auth-user-message {
|
|
align-items: flex-end;
|
|
.message-wrapper {
|
|
justify-content: flex-end;
|
|
}
|
|
.message-details {
|
|
align-items: flex-end;
|
|
}
|
|
.message-content {
|
|
background-color: #3f3f3f;
|
|
border-bottom-right-radius: 0 !important;
|
|
}
|
|
}
|
|
.automatic-message {
|
|
align-items: center;
|
|
.message-wrapper {
|
|
justify-content: center;
|
|
}
|
|
.message-details {
|
|
align-items: center;
|
|
}
|
|
.message-content {
|
|
background-color: #ffcb00;
|
|
width: 70%;
|
|
text-align: center;
|
|
}
|
|
}
|
|
.btn-sm {
|
|
width: 30px !important;
|
|
}
|
|
</style>
|