feature(frontend): Creation fixes

This commit is contained in:
Mateusz Michałowski 2024-08-08 18:02:13 +02:00
parent 6081b2f492
commit 40e534ab71
17 changed files with 679 additions and 478 deletions

View File

@ -11,7 +11,7 @@ body {
.bg-gradient {
background: rgb(4 112 6);
background: linear-gradient(90deg, rgb(4 112 6 / 100%) 22%, rgb(197 141 56 / 100%) 98%);
background: linear-gradient(90deg, rgb(4 112 6 / 100%) 22%, rgb(197 141 56 / 100%) 98%) !important;
color: white;
}
@ -328,3 +328,8 @@ a:hover,
box-shadow: 0 0 0 0 rgb(204 169 44 / 0%);
}
}
.transparent-button {
background-color: transparent;
border: none;
}

View File

@ -2,77 +2,134 @@
<div class="contribution-messages-formular">
<small class="pl-2 pt-3">{{ $t('form.reply') }}</small>
<div>
<b-form @submit.prevent="onSubmit" @reset="onReset">
<b-form-textarea
<BForm @submit.prevent="onSubmit" @reset="onReset">
<BFormTextarea
id="textarea"
v-model="form.text"
@update:model-value="form.text = $event"
:model-value="form.text"
:placeholder="$t('form.memo')"
rows="3"
></b-form-textarea>
></BFormTextarea>
<BRow class="mt-4 mb-4">
<BCol>
<b-button type="reset" variant="secondary">{{ $t('form.cancel') }}</b-button>
<BButton type="reset" variant="secondary">{{ $t('form.cancel') }}</BButton>
</BCol>
<BCol class="text-right">
<b-button type="submit" variant="gradido" :disabled="disabled">
<BButton type="submit" variant="gradido" :disabled="disabled">
{{ $t('form.reply') }}
</b-button>
</BButton>
</BCol>
</BRow>
</b-form>
</BForm>
</div>
</div>
</template>
<script>
import { createContributionMessage } from '../../graphql/mutations.js'
<!--<script>-->
<!--import { createContributionMessage } from '../../graphql/mutations.js'-->
export default {
name: 'ContributionMessagesFormular',
props: {
contributionId: {
type: Number,
required: true,
},
},
data() {
return {
form: {
text: '',
},
isSubmitting: false,
}
},
computed: {
disabled() {
return this.form.text === '' || this.isSubmitting
},
},
methods: {
onSubmit() {
this.isSubmitting = true
this.$apollo
.mutate({
mutation: createContributionMessage,
variables: {
contributionId: this.contributionId,
message: this.form.text,
},
})
.then((result) => {
this.$emit('get-list-contribution-messages', false)
this.$emit('update-status', this.contributionId)
this.form.text = ''
this.toastSuccess(this.$t('message.reply'))
this.isSubmitting = false
})
.catch((error) => {
this.toastError(error.message)
this.isSubmitting = false
})
},
onReset() {
this.form.text = ''
},
<!--export default {-->
<!-- name: 'ContributionMessagesFormular',-->
<!-- props: {-->
<!-- contributionId: {-->
<!-- type: Number,-->
<!-- required: true,-->
<!-- },-->
<!-- },-->
<!-- data() {-->
<!-- return {-->
<!-- form: {-->
<!-- text: '',-->
<!-- },-->
<!-- isSubmitting: false,-->
<!-- }-->
<!-- },-->
<!-- computed: {-->
<!-- disabled() {-->
<!-- return this.form.text === '' || this.isSubmitting-->
<!-- },-->
<!-- },-->
<!-- methods: {-->
<!-- onSubmit() {-->
<!-- this.isSubmitting = true-->
<!-- this.$apollo-->
<!-- .mutate({-->
<!-- mutation: createContributionMessage,-->
<!-- variables: {-->
<!-- contributionId: this.contributionId,-->
<!-- message: this.form.text,-->
<!-- },-->
<!-- })-->
<!-- .then((result) => {-->
<!-- this.$emit('get-list-contribution-messages', false)-->
<!-- this.$emit('update-status', this.contributionId)-->
<!-- this.form.text = ''-->
<!-- this.toastSuccess(this.$t('message.reply'))-->
<!-- this.isSubmitting = false-->
<!-- })-->
<!-- .catch((error) => {-->
<!-- this.toastError(error.message)-->
<!-- this.isSubmitting = false-->
<!-- })-->
<!-- },-->
<!-- onReset() {-->
<!-- this.form.text = ''-->
<!-- },-->
<!-- },-->
<!--}-->
<!--</script>-->
<script setup>
import { ref, computed } from 'vue'
import { useMutation } from '@vue/apollo-composable'
import { useI18n } from 'vue-i18n'
import { createContributionMessage } from '@/graphql/mutations.js'
import { useAppToast } from '@/composables/useToast'
const props = defineProps({
contributionId: {
type: Number,
required: true,
},
})
const emit = defineEmits(['get-list-contribution-messages', 'update-status'])
const { t } = useI18n()
const { toastSuccess, toastError } = useAppToast()
const { mutate: createContributionMessageMutation } = useMutation(createContributionMessage)
const form = ref({
text: '',
})
const isSubmitting = ref(false)
const disabled = computed(() => {
return form.value.text === '' || isSubmitting.value
})
async function onSubmit() {
isSubmitting.value = true
try {
await createContributionMessageMutation({
contributionId: props.contributionId,
message: form.value.text,
})
emit('get-list-contribution-messages', false)
emit('update-status', props.contributionId)
form.value.text = ''
toastSuccess(t('message.reply'))
} catch (error) {
toastError(error.message)
} finally {
isSubmitting.value = false
}
}
function onReset() {
form.value.text = ''
}
</script>

View File

@ -15,10 +15,10 @@
</div>
<div v-b-toggle="'collapse' + String(contributionId)" class="text-center pointer clearboth">
<b-button variant="outline-primary" block class="mb-3">
<b-icon icon="arrow-up-short"></b-icon>
<BButton variant="outline-primary" block class="mb-3">
<IBiArrowUpShort />
{{ $t('form.close') }}
</b-button>
</BButton>
</div>
</div>
</template>

View File

@ -8,9 +8,11 @@
<label>{{ $t('contribution.selectDate') }}</label>
<BFormInput
id="contribution-date"
v-model="form.date"
:model-value="date"
@update:model-value="date = $event"
:state="dataFieldMeta.valid"
:locale="$i18n.locale"
:max="maximalDate"
:max="getMaximalDate"
:min="minimalDate"
class="mb-4 bg-248"
reset-value=""
@ -29,35 +31,31 @@
<div v-else>
<input-textarea
id="contribution-memo"
v-model="form.memo"
:name="$t('form.message')"
name="memo"
:label="$t('contribution.activity')"
:placeholder="$t('contribution.yourActivity')"
:rules="{ required: true, min: 5, max: 255 }"
/>
<input-hour
v-model="form.hours"
:name="$t('form.hours')"
name="hours"
:label="$t('form.hours')"
placeholder="0.25"
:rules="{
required: true,
min: 0.25,
max: validMaxTime,
gddCreationTime: [0.25, validMaxTime],
gddCreationTime: { min: 0.25, max: validMaxTime },
}"
:valid-max-time="validMaxTime"
@updateAmount="updateAmount"
></input-hour>
/>
<input-amount
id="contribution-amount"
v-model="form.amount"
name="amount"
:label="$t('form.amount')"
placeholder="20"
:rules="{ required: true, gddSendAmount: { min: 20, max: validMaxGDD } }"
typ="ContributionForm"
></input-amount>
/>
<BRow class="mt-5">
<BCol cols="12" lg="6">
@ -66,7 +64,7 @@
type="reset"
variant="secondary"
data-test="button-cancel"
@click="reset"
@click="fullFormReset"
>
{{ $t('form.cancel') }}
</BButton>
@ -87,96 +85,123 @@
</BForm>
</div>
</template>
<script>
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import InputHour from '@/components/Inputs/InputHour'
import InputAmount from '@/components/Inputs/InputAmount'
import InputTextarea from '@/components/Inputs/InputTextarea'
import { useField, useForm } from 'vee-validate'
export default {
name: 'ContributionForm',
components: {
InputHour,
InputAmount,
InputTextarea,
const props = defineProps({
modelValue: { type: Object, required: true },
isThisMonth: { type: Boolean, required: true },
minimalDate: { type: Date, required: true },
maxGddLastMonth: { type: Number, required: true },
maxGddThisMonth: { type: Number, required: true },
})
const emit = defineEmits(['update-contribution', 'set-contribution'])
const { t } = useI18n()
const form = ref({ ...props.modelValue })
const {
values: formValues,
meta: formMeta,
resetForm,
defineField,
setFieldValue,
} = useForm({
initialValues: {
date: props.modelValue.date,
memo: props.modelValue.memo,
hours: props.modelValue.hours,
amount: props.modelValue.amount,
},
props: {
value: { type: Object, required: true },
isThisMonth: { type: Boolean, required: true },
minimalDate: { type: Date, required: true },
maxGddLastMonth: { type: Number, required: true },
maxGddThisMonth: { type: Number, required: true },
})
const [date, dateProps] = defineField('date')
const { meta: dataFieldMeta } = useField('date', 'required')
const showMessage = computed(() => {
if (props.maxGddThisMonth <= 0 && props.maxGddLastMonth <= 0) return true
if (props.modelValue.date)
return (
(props.isThisMonth && props.maxGddThisMonth <= 0) ||
(!props.isThisMonth && props.maxGddLastMonth <= 0)
)
return false
})
const disabled = computed(() => {
return (
!formMeta.value.valid ||
(props.isThisMonth && parseInt(form.value.amount) > parseInt(props.maxGddThisMonth)) ||
(!props.isThisMonth && parseInt(form.value.amount) > parseInt(props.maxGddLastMonth))
)
})
const validMaxGDD = computed(() => {
return Number(props.isThisMonth ? props.maxGddThisMonth : props.maxGddLastMonth)
})
const validMaxTime = computed(() => {
return Number(validMaxGDD.value / 20)
})
const noOpenCreation = computed(() => {
if (props.maxGddThisMonth <= 0 && props.maxGddLastMonth <= 0) {
return t('contribution.noOpenCreation.allMonth')
}
if (props.isThisMonth && props.maxGddThisMonth <= 0) {
return t('contribution.noOpenCreation.thisMonth')
}
if (!props.isThisMonth && props.maxGddLastMonth <= 0) {
return t('contribution.noOpenCreation.lastMonth')
}
return ''
})
const getMaximalDate = computed(() => {
return new Date().toISOString().slice(0, 10)
})
watch(
() => formValues.hours,
() => {
updateAmount(formValues.hours)
},
data() {
return {
minlength: 5,
maxlength: 255,
maximalDate: new Date(),
form: this.value, // includes 'id' and time
}
},
computed: {
showMessage() {
if (this.maxGddThisMonth <= 0 && this.maxGddLastMonth <= 0) return true
if (this.form.date)
return (
(this.isThisMonth && this.maxGddThisMonth <= 0) ||
(!this.isThisMonth && this.maxGddLastMonth <= 0)
)
return false
)
function updateAmount(hours) {
setFieldValue('amount', (hours * 20).toFixed(2).toString())
}
function submit() {
const dataToSave = { ...formValues }
let emitOption = 'set-contribution'
if (props.modelValue.id) {
dataToSave.id = props.modelValue.id
emitOption = 'update-contribution'
}
emit(emitOption, dataToSave)
fullFormReset()
}
function fullFormReset() {
resetForm({
values: {
id: null,
date: '',
memo: '',
hours: 0,
amount: '',
},
disabled() {
return (
this.form.date === '' ||
this.form.memo.length < this.minlength ||
this.form.memo.length > this.maxlength ||
this.form.amount === '' ||
parseInt(this.form.amount) <= 0 ||
parseInt(this.form.amount) > 1000 ||
(this.isThisMonth && parseInt(this.form.amount) > parseInt(this.maxGddThisMonth)) ||
(!this.isThisMonth && parseInt(this.form.amount) > parseInt(this.maxGddLastMonth))
)
},
validMaxGDD() {
return Number(this.isThisMonth ? this.maxGddThisMonth : this.maxGddLastMonth)
},
validMaxTime() {
return Number(this.validMaxGDD / 20)
},
noOpenCreation() {
if (this.maxGddThisMonth <= 0 && this.maxGddLastMonth <= 0) {
return this.$t('contribution.noOpenCreation.allMonth')
}
if (this.isThisMonth && this.maxGddThisMonth <= 0) {
return this.$t('contribution.noOpenCreation.thisMonth')
}
if (!this.isThisMonth && this.maxGddLastMonth <= 0) {
return this.$t('contribution.noOpenCreation.lastMonth')
}
return ''
},
},
watch: {
value() {
return (this.form = this.value)
},
},
methods: {
updateAmount(hours) {
this.form.amount = (hours * 20).toFixed(2).toString()
},
submit() {
this.$emit(this.form.id ? 'update-contribution' : 'set-contribution', { ...this.form })
this.reset()
},
reset() {
this.$refs.form.reset()
this.form.id = null
this.form.date = ''
this.form.memo = ''
this.form.hours = 0
this.form.amount = ''
},
},
})
}
</script>
<style>

View File

@ -6,7 +6,7 @@
v-bind="item"
:contribution-id="item.id"
:all-contribution="allContribution"
@closeAllOpenCollapse="$emit('closeAllOpenCollapse')"
@close-all-open-collapse="$emit('close-all-open-collapse')"
@update-contribution-form="updateContributionForm"
@delete-contribution="deleteContribution"
@update-status="updateStatus"
@ -18,13 +18,13 @@
v-bind="item2"
:contribution-id="item2.id"
:all-contribution="allContribution"
@closeAllOpenCollapse="$emit('closeAllOpenCollapse')"
@close-all-open-collapse="$emit('close-all-open-collapse')"
@update-contribution-form="updateContributionForm"
@delete-contribution="deleteContribution"
@update-status="updateStatus"
/>
</div>
<b-pagination
<BPagination
v-if="isPaginationVisible"
v-model="currentPage"
class="mt-3"
@ -34,7 +34,7 @@
:total-rows="contributionCount"
align="center"
:hide-ellipsis="true"
></b-pagination>
/>
</div>
</template>
<script>

View File

@ -13,12 +13,23 @@
color="#fff"
class="font-weight-bold"
></avatar>
<BAvatar v-else :icon="icon" :variant="variant" size="3em"></BAvatar>
<BAvatar v-else rounded="lg" :variant="variant" size="4em">
<IBiTrash v-if="deletedAt" />
<IBiXCircle v-else-if="deniedAt" />
<IBiCheck v-else-if="confirmedAt" />
<IBiQuestion v-else-if="status === 'IN_PROGRESS'" />
<IBiBellFill v-else style="width: 36px; height: 36px" />
</BAvatar>
</BCol>
<BCol>
<div v-if="firstName" class="mr-3 font-weight-bold">
{{ firstName }} {{ lastName }}
<b-icon :icon="icon" :variant="variant"></b-icon>
<IBiTrash v-if="deletedAt" />
<IBiXCircle v-else-if="deniedAt" />
<IBiCheck v-else-if="confirmedAt" />
<IBiQuestion v-else-if="status === 'IN_PROGRESS'" />
<IBiBellFill v-else />
<!-- <b-icon :icon="icon" :variant="variant"></b-icon>-->
</div>
<div class="small">
{{ $d(new Date(contributionDate), 'short') }}
@ -66,7 +77,7 @@
class="test-delete-contribution pointer mr-3"
@click="deleteContribution({ id })"
>
<b-icon icon="trash"></b-icon>
<IBiTrash />
<div>{{ $t('delete') }}</div>
</div>
@ -84,23 +95,21 @@
})
"
>
<!-- <b-icon icon="pencil"></b-icon>-->
<IBiPencil />
<div>{{ $t('edit') }}</div>
</div>
</BCol>
<BCol cols="6" class="text-center">
<div v-if="messagesCount > 0 && !moderatorId" class="pointer" @click="visible = !visible">
<!-- <b-icon icon="chat-dots"></b-icon>-->
<IBiChatDots />
<div>{{ $t('moderatorChat') }}</div>
</div>
</BCol>
</BRow>
<div v-else class="pb-3"></div>
<BCollapse :id="collapsId" v-model="visible" class="mt-2">
<BCollapse :id="collapsId" :model-value="visible" class="mt-2">
<contribution-messages-list
:messages="messages_get"
:messages="messagesGet"
:status="status"
:contribution-id="contributionId"
@get-list-contribution-messages="getListContributionMessages"
@ -110,159 +119,327 @@
</div>
</div>
</template>
<script>
<!--<script>-->
<!--import Avatar from 'vue-avatar'-->
<!--import CollapseIcon from '../TransactionRows/CollapseIcon'-->
<!--import ContributionMessagesList from '@/components/ContributionMessages/ContributionMessagesList'-->
<!--import { listContributionMessages } from '../../graphql/queries.js'-->
<!--export default {-->
<!-- name: 'ContributionListItem',-->
<!-- components: {-->
<!-- Avatar,-->
<!-- CollapseIcon,-->
<!-- ContributionMessagesList,-->
<!-- },-->
<!-- props: {-->
<!-- id: {-->
<!-- type: Number,-->
<!-- },-->
<!-- amount: {-->
<!-- type: String,-->
<!-- },-->
<!-- memo: {-->
<!-- type: String,-->
<!-- },-->
<!-- firstName: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- },-->
<!-- lastName: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- },-->
<!-- createdAt: {-->
<!-- type: String,-->
<!-- },-->
<!-- contributionDate: {-->
<!-- type: String,-->
<!-- },-->
<!-- deletedAt: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- },-->
<!-- confirmedBy: {-->
<!-- type: Number,-->
<!-- required: false,-->
<!-- },-->
<!-- confirmedAt: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- },-->
<!-- deniedBy: {-->
<!-- type: Number,-->
<!-- required: false,-->
<!-- },-->
<!-- deniedAt: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- },-->
<!-- updatedBy: {-->
<!-- type: Number,-->
<!-- required: false,-->
<!-- },-->
<!-- status: {-->
<!-- type: String,-->
<!-- required: false,-->
<!-- default: '',-->
<!-- },-->
<!-- messagesCount: {-->
<!-- type: Number,-->
<!-- required: false,-->
<!-- },-->
<!-- contributionId: {-->
<!-- type: Number,-->
<!-- required: true,-->
<!-- },-->
<!-- allContribution: {-->
<!-- type: Boolean,-->
<!-- required: false,-->
<!-- default: false,-->
<!-- },-->
<!-- moderatorId: {-->
<!-- type: Number,-->
<!-- required: false,-->
<!-- default: 0,-->
<!-- },-->
<!-- },-->
<!-- data() {-->
<!-- return {-->
<!-- inProcess: true,-->
<!-- messages_get: [],-->
<!-- visible: false,-->
<!-- }-->
<!-- },-->
<!-- computed: {-->
<!-- icon() {-->
<!-- if (this.deletedAt) return 'trash'-->
<!-- if (this.deniedAt) return 'x-circle'-->
<!-- if (this.confirmedAt) return 'check'-->
<!-- if (this.status === 'IN_PROGRESS') return 'question'-->
<!-- return `<IBiBellFill />`-->
<!-- },-->
<!-- variant() {-->
<!-- if (this.deletedAt) return 'danger'-->
<!-- if (this.deniedAt) return 'warning'-->
<!-- if (this.confirmedAt) return 'success'-->
<!-- if (this.status === 'IN_PROGRESS') return '205'-->
<!-- return 'primary'-->
<!-- },-->
<!-- date() {-->
<!-- return this.createdAt-->
<!-- },-->
<!-- collapsId() {-->
<!-- return 'collapse' + String(this.id)-->
<!-- },-->
<!-- username() {-->
<!-- return {-->
<!-- username: `${this.firstName} ${this.lastName}`,-->
<!-- initials: `${this.firstName[0]}${this.lastName[0]}`,-->
<!-- }-->
<!-- },-->
<!-- },-->
<!-- watch: {-->
<!-- visible() {-->
<!-- if (this.visible) this.getListContributionMessages()-->
<!-- },-->
<!-- },-->
<!-- methods: {-->
<!-- deleteContribution(item) {-->
<!-- this.$bvModal.msgBoxConfirm(this.$t('contribution.delete')).then(async (value) => {-->
<!-- if (value) this.$emit('delete-contribution', item)-->
<!-- })-->
<!-- },-->
<!-- getListContributionMessages(closeCollapse = true) {-->
<!-- if (closeCollapse) {-->
<!-- this.$emit('closeAllOpenCollapse')-->
<!-- }-->
<!-- this.$apollo-->
<!-- .query({-->
<!-- query: listContributionMessages,-->
<!-- variables: {-->
<!-- contributionId: this.contributionId,-->
<!-- },-->
<!-- fetchPolicy: 'no-cache',-->
<!-- })-->
<!-- .then((result) => {-->
<!-- this.messages_get = result.data.listContributionMessages.messages-->
<!-- })-->
<!-- .catch((error) => {-->
<!-- this.toastError(error.message)-->
<!-- })-->
<!-- },-->
<!-- updateStatus(id) {-->
<!-- this.$emit('update-status', id)-->
<!-- },-->
<!-- },-->
<!--}-->
<!--</script>-->
<script setup>
import { ref, computed, watch } from 'vue'
import Avatar from 'vue-avatar'
import CollapseIcon from '../TransactionRows/CollapseIcon'
import ContributionMessagesList from '@/components/ContributionMessages/ContributionMessagesList'
import { listContributionMessages } from '../../graphql/queries.js'
import { useAppToast } from '@/composables/useToast'
import { useI18n } from 'vue-i18n'
import { useQuery } from '@vue/apollo-composable'
export default {
name: 'ContributionListItem',
components: {
Avatar,
CollapseIcon,
ContributionMessagesList,
const props = defineProps({
id: {
type: Number,
},
props: {
id: {
type: Number,
},
amount: {
type: String,
},
memo: {
type: String,
},
firstName: {
type: String,
required: false,
},
lastName: {
type: String,
required: false,
},
createdAt: {
type: String,
},
contributionDate: {
type: String,
},
deletedAt: {
type: String,
required: false,
},
confirmedBy: {
type: Number,
required: false,
},
confirmedAt: {
type: String,
required: false,
},
deniedBy: {
type: Number,
required: false,
},
deniedAt: {
type: String,
required: false,
},
updatedBy: {
type: Number,
required: false,
},
status: {
type: String,
required: false,
default: '',
},
messagesCount: {
type: Number,
required: false,
},
contributionId: {
type: Number,
required: true,
},
allContribution: {
type: Boolean,
required: false,
default: false,
},
moderatorId: {
type: Number,
required: false,
default: 0,
},
amount: {
type: String,
},
data() {
return {
inProcess: true,
messages_get: [],
visible: false,
memo: {
type: String,
},
firstName: {
type: String,
required: false,
},
lastName: {
type: String,
required: false,
},
createdAt: {
type: String,
},
contributionDate: {
type: String,
},
deletedAt: {
type: String,
required: false,
},
confirmedBy: {
type: Number,
required: false,
},
confirmedAt: {
type: String,
required: false,
},
deniedBy: {
type: Number,
required: false,
},
deniedAt: {
type: String,
required: false,
},
updatedBy: {
type: Number,
required: false,
},
status: {
type: String,
required: false,
default: '',
},
messagesCount: {
type: Number,
required: false,
},
contributionId: {
type: Number,
required: true,
},
allContribution: {
type: Boolean,
required: false,
default: false,
},
moderatorId: {
type: Number,
required: false,
default: 0,
},
})
const { toastError, toastSuccess } = useAppToast()
const { t } = useI18n()
const inProcess = ref(true)
const messagesGet = ref([])
const visible = ref(false)
const icon = computed(() => {
if (props.deletedAt) return 'trash'
if (props.deniedAt) return 'x-circle'
if (props.confirmedAt) return 'check'
if (props.status === 'IN_PROGRESS') return 'question'
return `<IBiBellFill />`
})
const variant = computed(() => {
if (props.deletedAt) return 'danger'
if (props.deniedAt) return 'warning'
if (props.confirmedAt) return 'success'
if (props.status === 'IN_PROGRESS') return '205'
return 'primary'
})
const date = computed(() => props.createdAt)
const collapsId = computed(() => 'collapse' + String(props.id))
const username = computed(() => ({
username: `${props.firstName} ${props.lastName}`,
initials: `${props.firstName[0]}${props.lastName[0]}`,
}))
watch(
() => visible.value,
() => {
if (visible.value) getListContributionMessages()
},
)
function deleteContribution(item) {
if (window.confirm(t('contribution.delete'))) {
emit('delete-contribution', item)
}
}
const { onResult, result, loading, error, refetch } = useQuery(listContributionMessages, {
contributionId: props.contributionId,
})
function getListContributionMessages(closeCollapse = true) {
if (closeCollapse) {
emit('close-all-open-collapse')
}
refetch({
contributionId: props.contributionId,
}).catch((err) => {
toastError(err.message)
})
}
onResult((resultValue) => {
if (resultValue.data) {
messagesGet.value.length = 0
resultValue.data.listContributionMessages.messages.forEach((message) => {
messagesGet.value.push(message)
})
}
})
watch(
() => visible.value,
() => {
if (visible.value) {
getListContributionMessages()
}
},
computed: {
icon() {
if (this.deletedAt) return 'trash'
if (this.deniedAt) return 'x-circle'
if (this.confirmedAt) return 'check'
if (this.status === 'IN_PROGRESS') return 'question'
return 'bell-fill'
},
variant() {
if (this.deletedAt) return 'danger'
if (this.deniedAt) return 'warning'
if (this.confirmedAt) return 'success'
if (this.status === 'IN_PROGRESS') return '205'
return 'primary'
},
date() {
return this.createdAt
},
collapsId() {
return 'collapse' + String(this.id)
},
username() {
return {
username: `${this.firstName} ${this.lastName}`,
initials: `${this.firstName[0]}${this.lastName[0]}`,
}
},
},
watch: {
visible() {
if (this.visible) this.getListContributionMessages()
},
},
methods: {
deleteContribution(item) {
this.$bvModal.msgBoxConfirm(this.$t('contribution.delete')).then(async (value) => {
if (value) this.$emit('delete-contribution', item)
})
},
getListContributionMessages(closeCollapse = true) {
if (closeCollapse) {
this.$emit('closeAllOpenCollapse')
}
this.$apollo
.query({
query: listContributionMessages,
variables: {
contributionId: this.contributionId,
},
fetchPolicy: 'no-cache',
})
.then((result) => {
this.messages_get = result.data.listContributionMessages.messages
})
.catch((error) => {
this.toastError(error.message)
})
},
updateStatus(id) {
this.$emit('update-status', id)
},
},
)
function updateStatus(id) {
emit('update-status', id)
}
const emit = defineEmits(['delete-contribution', 'close-all-open-collapse', 'update-status'])
</script>

View File

@ -293,7 +293,7 @@ const userName = ref('')
const recipientCommunity = ref({ uuid: '', name: '' })
// Use vee-validate's useForm
const { handleSubmit, values, meta, resetForm, defineField } = useForm({
const { handleSubmit, resetForm, defineField } = useForm({
initialValues: {
identifier: props.identifier,
amount: props.amount ? String(props.amount) : '',

View File

@ -1,12 +1,5 @@
<template>
<div class="input-amount">
<!-- <validation-provider-->
<!-- v-if="typ === 'TransactionForm'"-->
<!-- tag="div"-->
<!-- :rules="rules"-->
<!-- :name="name"-->
<!-- v-slot="{ errors, valid, validated, ariaInput, ariaMsg }"-->
<!-- >-->
<template v-if="typ === 'TransactionForm'">
<BFormGroup :label="label" :label-for="labelFor" data-test="input-amount">
<BFormInput
@ -24,14 +17,12 @@
@update:model-value="normalizeAmount($event)"
@focus="amountFocused = true"
@blur="normalizeAmount($event)"
></BFormInput>
/>
<BFormInvalidFeedback v-if="errorMessage">
{{ errorMessage }}
</BFormInvalidFeedback>
</BFormGroup>
</template>
<!-- </validation-provider>-->
<BInputGroup v-else append="GDD" :label="label" :label-for="labelFor">
<BFormInput
:id="labelFor"
@ -42,12 +33,8 @@
type="text"
readonly
trim
@update:model-value="normalizeAmount($event)"
@focus="amountFocused = true"
@blur="normalizeAmount($event)"
></BFormInput>
/>
</BInputGroup>
<pre>{{ value }}</pre>
</div>
</template>
<!--<script>-->

View File

@ -26,7 +26,6 @@
<div class="input-hour">
<BFormGroup :label="label" :label-for="labelFor">
<BFormInput
v-bind="ariaInput"
:id="labelFor"
:model-value="currentValue"
:name="name"
@ -37,8 +36,11 @@
min="0"
:max="validMaxTime"
class="bg-248"
@update:modelValue="currentValue"
@update:model-value="currentValue = $event"
/>
<BFormInvalidFeedback v-if="errorMessage">
{{ errorMessage }}
</BFormInvalidFeedback>
</BFormGroup>
</div>
</template>
@ -82,7 +84,6 @@
import { ref, computed, watch } from 'vue'
import { useField } from 'vee-validate'
// Props
const props = defineProps({
rules: {
type: Object,
@ -100,42 +101,13 @@ const props = defineProps({
type: String,
required: true,
},
modelValue: {
type: Number,
required: true,
default: 0,
},
validMaxTime: {
type: Number,
required: true,
},
})
// Emits
const emit = defineEmits(['update:modelValue', 'updateAmount'])
const { value: currentValue, errorMessage, meta } = useField(props.name, props.rules)
// Use vee-validate's useField
const { value: currentValue, meta } = useField(props.name, props.rules, {
initialValue: props.modelValue,
})
// Computed
const labelFor = computed(() => `${props.name}-input-field`)
// Watch for external value changes
watch(
() => props.modelValue,
(newValue) => {
if (newValue !== currentValue.value) {
currentValue.value = newValue
emit('updateAmount', newValue)
}
},
)
// Watch for internal value changes
watch(currentValue, (newValue) => {
emit('update:modelValue', Number(newValue))
emit('updateAmount', Number(newValue))
})
</script>

View File

@ -13,7 +13,7 @@
<span class="ml-2">{{ $t('navigation.overview') }}</span>
</BNavItem>
<BNavItem to="/send" class="mb-3" active-class="active-route">
<b-icon icon="cash" aria-hidden="true"></b-icon>
<IBiCash />
<span class="ml-2">{{ $t('navigation.send') }}</span>
</BNavItem>
<BNavItem to="/transactions" :class="transactionClass" active-class="active-route">
@ -57,7 +57,7 @@
active-class="active-route"
@click="$emit('admin')"
>
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
<IBiShieldCheck />
<span class="ml-2">
{{ $t('navigation.admin_area') }}
</span>
@ -92,7 +92,6 @@ export default {
return 'mb-3'
},
isHumhub() {
// return true
return CONFIG.HUMHUB_ACTIVE === 'true'
},
isGMS() {

View File

@ -1,5 +1,5 @@
<template>
<div class="community-member mt-3 mt-lg-0">
<div class="community-member mt-3 mt-lg-0 position-relative">
<div class="text-center bg-gradient">
<BBadge class="position-absolute mt--2 ml--5 px-3 bg-gradient">
{{ $t('member') }}

View File

@ -42,7 +42,7 @@
<!-- class="mr-3 gradido-global-border-color-accent pointer hover-icon"-->
<!-- @click="updateHideAmountGDD"-->
<!-- ></b-icon>-->
<button @click="updateHideAmountGDD">
<button class="transparent-button" @click="updateHideAmountGDD">
<IBiEyeSlash v-if="hideAmount" />
<IBiEye v-else />
</button>

View File

@ -25,10 +25,10 @@
<!-- ></b-icon>-->
<IBiLayers />
<span v-if="hideAmount" class="font-weight-bold gradido-global-color-accent">
{{ $t('asterisks') }}
{{ t('asterisks') }}
</span>
<span v-else class="font-weight-bold gradido-global-color-accent">
{{ $n(GdtBalance, 'decimal') }} {{ $t('GDT') }}
{{ n(gdtBalance, 'decimal') }} {{ t('GDT') }}
</span>
</BCol>
<BCol cols="3" class="border-left border-light">
@ -37,7 +37,7 @@
<!-- class="mr-3 gradido-global-border-color-accent pointer hover-icon"-->
<!-- @click="updateHideAmountGDT"-->
<!-- ></b-icon>-->
<button @click="updateHideAmountGDT">
<button class="transparent-button" @click="updateHideAmountGDT">
<IBiEyeSlash v-if="hideAmount" />
<IBiEye v-else />
</button>
@ -95,14 +95,14 @@ import { updateUserInfos } from '@/graphql/mutations'
import { useAppToast } from '../../../composables/useToast'
const props = defineProps({
GdtBalance: { type: Number, required: true },
gdtBalance: { type: Number, required: true },
badgeShow: { type: Boolean, default: true },
showStatus: { type: Boolean, default: false },
})
const store = useStore()
const { mutate } = useMutation(updateUserInfos)
const { t } = useI18n()
const { t, n } = useI18n()
const { toastSuccess, toastError } = useAppToast()
const hideAmount = computed(() => store.state.hideAmountGDT)

View File

@ -1,18 +1,38 @@
<template>
<div class="nav-community">
<div class="bg-209 rounded-26 d-flex bd-highlight mx-xl-6 mx-lg-5 shadow">
<b-btn to="contribute" active-class="btn-active svg-icon-active" block variant="link">
<div
class="nav-community__btn-wrapper bg-209 rounded-26 d-flex bd-highlight mx-xl-6 mx-lg-5 shadow justify-content-between"
>
<BButton
to="contribute"
active-class="btn-active svg-icon-active"
block
variant="link"
class="nav-community__btn"
>
<b-img src="/img/svg/write.svg" height="20" class="svg-icon" />
{{ $t('community.submitContribution') }}
</b-btn>
<b-btn to="contributions" active-class="btn-active svg-icon-active" block variant="link">
</BButton>
<BButton
to="contributions"
active-class="btn-active svg-icon-active"
block
variant="link"
class="nav-community__btn"
>
<b-img src="/img/svg/my_profil.svg" height="20" class="svg-icon" />
{{ $t('community.myContributions') }}
</b-btn>
<b-btn to="community" active-class="btn-active svg-icon-active" block variant="link">
</BButton>
<BButton
to="community"
active-class="btn-active svg-icon-active"
block
variant="link"
class="nav-community__btn"
>
<b-img src="/img/svg/community.svg" height="20" class="svg-icon" />
{{ $t('community.community') }}
</b-btn>
</BButton>
</div>
</div>
</template>
@ -21,29 +41,33 @@ export default {
name: 'NavCommunity',
}
</script>
<style scoped>
.btn {
background-color: rgb(209 209 209);
color: black;
padding-right: 0;
padding-left: 0;
<style scoped lang="scss">
.nav-community__btn-wrapper {
> :deep(*) {
width: calc(100% / 3);
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
font-size: 14px;
text-wrap: nowrap;
color: black;
}
}
.btn-block + .btn-block {
margin-top: 0;
}
.svg-icon {
:deep(.svg-icon) {
filter: brightness(0) invert(0);
}
.btn-active {
:deep(.router-link-active) {
background-color: rgb(23 141 129);
color: white;
font-weight: bold;
padding: 0.625rem 1.25rem;
border-radius: 25px;
}
.btn-active .svg-icon {
:deep(.router-link-active .svg-icon) {
filter: brightness(0) invert(1);
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="community-page">
<div>
<BTabs v-model="tabIndex" no-nav-style borderless align="center">
<BTabs :model-value="tabIndex" no-nav-style borderless align="center">
<BTab no-body>
<open-creations-amount
:minimal-date="minimalDate"
@ -10,7 +10,8 @@
/>
<div class="mb-3"></div>
<contribution-form
v-model="form"
:model-value="form"
:key="computedKeyFromForm"
:is-this-month="isThisMonth"
:minimal-date="minimalDate"
:max-gdd-last-month="maxForMonths[0]"
@ -29,7 +30,7 @@
:contribution-count="contributionCount"
:show-pagination="true"
:page-size="pageSize"
@closeAllOpenCollapse="closeAllOpenCollapse"
@close-all-open-collapse="closeAllOpenCollapse"
@update-list-contributions="handleUpdateListContributions"
@update-contribution-form="handleUpdateContributionForm"
@delete-contribution="handleDeleteContribution"
@ -311,15 +312,13 @@ import ContributionForm from '@/components/Contributions/ContributionForm'
import ContributionList from '@/components/Contributions/ContributionList'
import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations'
import { listContributions, listAllContributions, openCreations } from '@/graphql/queries'
import { useAppToast } from '../composables/useToast'
import { useAppToast } from '@/composables/useToast'
import { useI18n } from 'vue-i18n'
const COMMUNITY_TABS = ['contribute', 'contributions', 'community']
// Props and emits
const emit = defineEmits(['update-transactions'])
// Router
const route = useRoute()
const router = useRouter()
@ -380,6 +379,10 @@ const maxForMonths = computed(() => {
return [0, 0]
})
const computedKeyFromForm = computed(() => {
return `${form.value.id}_${form.value.date}_${form.value.memo}_${form.value.amount}_${form.value.hours}`
})
// Queries
const { onResult: onOpenCreationsResult, refetch: refetchOpenCreations } = useQuery(openCreations)
const { onResult: onListAllContributionsResult, refetch: refetchAllContributions } = useQuery(
@ -412,22 +415,28 @@ onOpenCreationsResult(({ data }) => {
})
onListAllContributionsResult(({ data }) => {
console.count('RESULT?!')
if (data) {
contributionCountAll.value = data.listAllContributions.contributionCount
itemsAll.value = data.listAllContributions.contributionList
itemsAll.value.length = 0
data.listAllContributions.contributionList.forEach((entry) => {
itemsAll.value.push(entry)
})
}
})
onListContributionsResult(({ data }) => {
if (data) {
contributionCount.value = data.listContributions.contributionCount
items.value = data.listContributions.contributionList
items.value.length = 0
data.listContributions.contributionList.forEach((entry) => {
items.value.push({ ...entry })
})
if (items.value.find((item) => item.status === 'IN_PROGRESS')) {
tabIndex.value = 1
if (route.params.tab !== 'contributions') {
router.push({ params: { tab: 'contributions' } })
}
// Assuming toastInfo is available globally or imported
toastInfo(t('contribution.alert.answerQuestionToast'))
}
}
@ -456,11 +465,9 @@ const refetchData = () => {
const handleSaveContribution = async (data) => {
try {
await createContributionMutation({
variables: {
creationDate: data.date,
memo: data.memo,
amount: data.amount,
},
creationDate: data.date,
memo: data.memo,
amount: data.amount,
})
toastSuccess(t('contribution.submitted'))
refetchData()
@ -472,12 +479,10 @@ const handleSaveContribution = async (data) => {
const handleUpdateContribution = async (data) => {
try {
await updateContributionMutation({
variables: {
contributionId: data.id,
creationDate: data.date,
memo: data.memo,
amount: data.amount,
},
contributionId: data.id,
creationDate: data.date,
memo: data.memo,
amount: data.amount,
})
toastSuccess(t('contribution.updated'))
refetchData()
@ -489,7 +494,7 @@ const handleUpdateContribution = async (data) => {
const handleDeleteContribution = async (data) => {
try {
await deleteContributionMutation({
variables: { id: data.id },
id: data.id,
})
toastSuccess(t('contribution.deleted'))
refetchData()
@ -513,7 +518,7 @@ const handleUpdateListContributions = (pagination) => {
const handleUpdateContributionForm = (item) => {
form.value = {
id: item.id,
date: item.contributionDate,
date: new Date(item.contributionDate).toISOString().slice(0, 10),
memo: item.memo,
amount: item.amount,
hours: item.amount / 20,
@ -530,7 +535,9 @@ const updateTransactions = (pagination) => {
const updateStatus = (id) => {
const item = items.value.find((item) => item.id === id)
if (item) item.status = 'PENDING'
if (item) {
item.status = 'PENDING'
}
}
// Watchers

View File

@ -1,5 +1,5 @@
import CONFIG from '../config'
import { store } from '../store/store'
import { store } from '@/store/store'
import router from '../routes/router'
import i18n from '../i18n'
import { createHttpLink, ApolloLink, ApolloClient, InMemoryCache } from '@apollo/client/core'
@ -18,7 +18,7 @@ const authLink = new ApolloLink((operation, forward) => {
})
return forward(operation).map((response) => {
if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') {
response.errors[0].message = i18n.t('error.session-expired')
response.errors[0].message = i18n.global.t('error.session-expired')
store.dispatch('logout', null)
if (router.currentRoute.path !== '/login') router.push('/login')
return response

View File

@ -2146,11 +2146,6 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-regex@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@ -2170,11 +2165,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
ansi-styles@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@ -3581,11 +3571,6 @@ dotenv@^8.2.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"
integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
editorconfig@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.4.tgz#040c9a8e9a6c5288388b87c2db07028aa89f53a3"
@ -3616,11 +3601,6 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-regex@^9.2.2:
version "9.2.2"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@ -7781,7 +7761,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -7790,14 +7770,14 @@ string-length@^4.0.1:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
string-width@4.2.2, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3, string-width@^5.1.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
dependencies:
eastasianwidth "^0.2.0"
emoji-regex "^9.2.2"
strip-ansi "^7.0.1"
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
string.prototype.trim@^1.2.9:
version "1.2.9"
@ -7827,27 +7807,13 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@^7.0.1, strip-ansi@^7.1.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==
dependencies:
ansi-regex "^2.0.0"
strip-ansi@^7.0.1, strip-ansi@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
dependencies:
ansi-regex "^6.0.1"
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@ -8860,7 +8826,7 @@ word-wrap@^1.2.5:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^6.2.0, wrap-ansi@^8.1.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@ -8869,24 +8835,6 @@ word-wrap@^1.2.5:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
dependencies:
ansi-styles "^6.1.0"
string-width "^5.0.1"
strip-ansi "^7.0.1"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"