standardization of policies/permissions
This commit is contained in:
parent
c60033b365
commit
188c4435cb
@ -13,6 +13,13 @@ class MutationResource extends BaseResource
|
|||||||
*/
|
*/
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return parent::toArray($request);
|
$data = parent::toArray($request);
|
||||||
|
|
||||||
|
$data['can'] = [
|
||||||
|
'update' => $request->user()?->can('update', $this->resource) ?? false,
|
||||||
|
'void' => $request->user()?->can('void', $this->resource) ?? false,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,8 +24,9 @@ class MutationPolicy
|
|||||||
public function update(User $user, Mutation $mutation): bool
|
public function update(User $user, Mutation $mutation): bool
|
||||||
{
|
{
|
||||||
$dynamic = $mutation->ledger->dynamic;
|
$dynamic = $mutation->ledger->dynamic;
|
||||||
|
$isOwner = $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||||
|
|
||||||
return $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
return $isOwner && $mutation->status === 'pending';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +35,8 @@ class MutationPolicy
|
|||||||
public function void(User $user, Mutation $mutation): bool
|
public function void(User $user, Mutation $mutation): bool
|
||||||
{
|
{
|
||||||
$dynamic = $mutation->ledger->dynamic;
|
$dynamic = $mutation->ledger->dynamic;
|
||||||
|
$isOwner = $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
||||||
|
|
||||||
return $dynamic->participants()->where('user_id', $user->id)->where('role', 'owner')->exists();
|
return $isOwner && $mutation->status !== 'voided';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,13 +17,16 @@ const props = defineProps<{
|
|||||||
created_at: string;
|
created_at: string;
|
||||||
chat: any;
|
chat: any;
|
||||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||||
|
can: {
|
||||||
|
update: boolean;
|
||||||
|
void: boolean;
|
||||||
|
};
|
||||||
}>;
|
}>;
|
||||||
participants?: Array<{
|
participants?: Array<{
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
pivot?: { role: string };
|
pivot?: { role: string };
|
||||||
}>;
|
}>;
|
||||||
isOwner: boolean;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@ -167,25 +170,25 @@ function getAmountClass(amount: number): string {
|
|||||||
|
|
||||||
<!-- Owner Approve/Reject Actions -->
|
<!-- Owner Approve/Reject Actions -->
|
||||||
<div
|
<div
|
||||||
v-if="isOwner && (mutation.status === 'pending' || mutation.status === 'approved')"
|
v-if="mutation.can.update || mutation.can.void"
|
||||||
class="c-mutation-list__actions"
|
class="c-mutation-list__actions"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-if="mutation.status === 'pending'"
|
v-if="mutation.can.update"
|
||||||
@click="updateStatus(mutation.id, 'approved')"
|
@click="updateStatus(mutation.id, 'approved')"
|
||||||
class="c-mutation-list__approve-btn"
|
class="c-mutation-list__approve-btn"
|
||||||
>
|
>
|
||||||
Approve
|
Approve
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="mutation.status === 'pending'"
|
v-if="mutation.can.update"
|
||||||
@click="updateStatus(mutation.id, 'rejected')"
|
@click="updateStatus(mutation.id, 'rejected')"
|
||||||
class="c-mutation-list__reject-btn"
|
class="c-mutation-list__reject-btn"
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="mutation.status !== 'voided'"
|
v-if="mutation.can.void"
|
||||||
@click="voidMutation(mutation.id)"
|
@click="voidMutation(mutation.id)"
|
||||||
class="c-mutation-list__void-btn"
|
class="c-mutation-list__void-btn"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -2,22 +2,26 @@
|
|||||||
import { Head, useForm } from '@inertiajs/vue3';
|
import { Head, useForm } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
layout: {
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Create',
|
||||||
|
href: route('dynamics.create'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
name: '',
|
name: '',
|
||||||
rules: '',
|
rules: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Create',
|
|
||||||
href: route('dynamics.create'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
form.post(route('dynamics.store'));
|
form.post(route('dynamics.store'));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,17 @@
|
|||||||
import { Head, Link } from '@inertiajs/vue3';
|
import { Head, Link } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
layout: {
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
dynamics: Array<{
|
dynamics: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
@ -9,13 +20,6 @@ defineProps<{
|
|||||||
rules: string;
|
rules: string;
|
||||||
}>;
|
}>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -1,7 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, useForm } from '@inertiajs/vue3';
|
import { Head, useForm } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
|
||||||
|
defineOptions({
|
||||||
|
layout: (props: any) => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: props.dynamic.name,
|
||||||
|
href: route('dynamics.show', props.dynamic.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Invite User',
|
||||||
|
href: route('dynamics.invitations.create', props.dynamic.id),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
dynamic: {
|
dynamic: {
|
||||||
@ -15,21 +33,6 @@ const form = useForm({
|
|||||||
role: 'participant',
|
role: 'participant',
|
||||||
});
|
});
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Invite User',
|
|
||||||
href: route('dynamics.invitations.create', props.dynamic.id),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
form.post(route('dynamics.invitations.store', props.dynamic.id), {
|
form.post(route('dynamics.invitations.store', props.dynamic.id), {
|
||||||
onSuccess: () => form.reset(),
|
onSuccess: () => form.reset(),
|
||||||
|
|||||||
@ -1,7 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, useForm, Link as InertiaLink } from '@inertiajs/vue3';
|
import { Head, useForm, Link as InertiaLink } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
|
||||||
|
defineOptions({
|
||||||
|
layout: (props: any) => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: props.dynamic.name,
|
||||||
|
href: route('dynamics.show', props.dynamic.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Settings',
|
||||||
|
href: route('dynamics.edit', props.dynamic.id),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
dynamic: {
|
dynamic: {
|
||||||
@ -16,21 +34,6 @@ const form = useForm({
|
|||||||
rules: props.dynamic.rules,
|
rules: props.dynamic.rules,
|
||||||
});
|
});
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Settings',
|
|
||||||
href: route('dynamics.edit', props.dynamic.id),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
form.patch(route('dynamics.update', props.dynamic.id));
|
form.patch(route('dynamics.update', props.dynamic.id));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,18 +43,6 @@ const props = defineProps<{
|
|||||||
update: boolean;
|
update: boolean;
|
||||||
}
|
}
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -1,30 +1,33 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, useForm } from '@inertiajs/vue3';
|
import { Head, useForm } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
|
||||||
import CreateLedgerForm from '@/components/CreateLedgerForm.vue';
|
import CreateLedgerForm from '@/components/CreateLedgerForm.vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
layout: (props: any) => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: props.dynamic.name,
|
||||||
|
href: route('dynamics.show', props.dynamic.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Create Ledger',
|
||||||
|
href: route('dynamics.ledgers.create', props.dynamic.id),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
dynamic: {
|
dynamic: {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Create Ledger',
|
|
||||||
href: route('dynamics.ledgers.create', props.dynamic.id),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -1,7 +1,29 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, useForm } from '@inertiajs/vue3';
|
import { Head, useForm, Link } from '@inertiajs/vue3';
|
||||||
import { route } from 'ziggy-js';
|
import { route } from 'ziggy-js';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
|
||||||
|
defineOptions({
|
||||||
|
layout: (props: any) => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
title: 'Dynamics',
|
||||||
|
href: route('dynamics.index'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: props.dynamic.name,
|
||||||
|
href: route('dynamics.show', props.dynamic.id),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: props.ledger.name,
|
||||||
|
href: route('dynamics.ledgers.show', [props.dynamic.id, props.ledger.id]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Edit',
|
||||||
|
href: route('dynamics.ledgers.edit', [props.dynamic.id, props.ledger.id]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
dynamic: {
|
dynamic: {
|
||||||
@ -20,25 +42,6 @@ const form = useForm({
|
|||||||
rules: props.ledger.rules,
|
rules: props.ledger.rules,
|
||||||
});
|
});
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.ledger.name,
|
|
||||||
href: route('dynamics.ledgers.show', [props.dynamic.id, props.ledger.id]),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Edit',
|
|
||||||
href: route('dynamics.ledgers.edit', [props.dynamic.id, props.ledger.id]),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
form.put(route('dynamics.ledgers.update', [props.dynamic.id, props.ledger.id]));
|
form.put(route('dynamics.ledgers.update', [props.dynamic.id, props.ledger.id]));
|
||||||
}
|
}
|
||||||
@ -47,45 +50,43 @@ function submit() {
|
|||||||
<template>
|
<template>
|
||||||
<Head title="Edit Ledger" />
|
<Head title="Edit Ledger" />
|
||||||
|
|
||||||
<AppLayout :breadcrumbs="breadcrumbs">
|
<div class="c-ledger-edit">
|
||||||
<div class="c-ledger-edit">
|
<div class="c-ledger-edit__container">
|
||||||
<div class="c-ledger-edit__container">
|
<div class="c-ledger-edit__card">
|
||||||
<div class="c-ledger-edit__card">
|
<div class="c-ledger-edit__body">
|
||||||
<div class="c-ledger-edit__body">
|
<h3 class="c-ledger-edit__title">
|
||||||
<h3 class="c-ledger-edit__title">
|
Edit {{ ledger.name }}
|
||||||
Edit {{ ledger.name }}
|
</h3>
|
||||||
</h3>
|
|
||||||
|
|
||||||
<form @submit.prevent="submit" class="c-ledger-edit__form">
|
<form @submit.prevent="submit" class="c-ledger-edit__form">
|
||||||
<div class="c-ledger-edit__field">
|
<div class="c-ledger-edit__field">
|
||||||
<label for="name" class="c-ledger-edit__label">Name</label>
|
<label for="name" class="c-ledger-edit__label">Name</label>
|
||||||
<input v-model="form.name" id="name" type="text" class="c-ledger-edit__input" />
|
<input v-model="form.name" id="name" type="text" class="c-ledger-edit__input" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-ledger-edit__field">
|
<div class="c-ledger-edit__field">
|
||||||
<label for="rules" class="c-ledger-edit__label">Rules</label>
|
<label for="rules" class="c-ledger-edit__label">Rules</label>
|
||||||
<textarea v-model="form.rules" id="rules" rows="4" class="c-ledger-edit__textarea"></textarea>
|
<textarea v-model="form.rules" id="rules" rows="4" class="c-ledger-edit__textarea"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-ledger-edit__actions">
|
<div class="c-ledger-edit__actions">
|
||||||
<button type="submit" :disabled="form.processing" class="c-ledger-edit__submit-btn">
|
<button type="submit" :disabled="form.processing" class="c-ledger-edit__submit-btn">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
<Link
|
<Link
|
||||||
:href="route('dynamics.ledgers.close', [dynamic.id, ledger.id])"
|
:href="route('dynamics.ledgers.close', [dynamic.id, ledger.id])"
|
||||||
method="put"
|
method="put"
|
||||||
as="button"
|
as="button"
|
||||||
class="c-ledger-edit__submit-btn c-ledger-edit__submit-btn--danger"
|
class="c-ledger-edit__submit-btn c-ledger-edit__submit-btn--danger"
|
||||||
>
|
>
|
||||||
Close Ledger
|
Close Ledger
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AppLayout>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -43,6 +43,7 @@ const props = defineProps<{
|
|||||||
score: number;
|
score: number;
|
||||||
rules: string;
|
rules: string;
|
||||||
alignment: string;
|
alignment: string;
|
||||||
|
status: string;
|
||||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||||
mutations: Array<{
|
mutations: Array<{
|
||||||
id: number;
|
id: number;
|
||||||
@ -56,30 +57,15 @@ const props = defineProps<{
|
|||||||
media?: Array<{ id: number; url: string; mime_type: string }>;
|
media?: Array<{ id: number; url: string; mime_type: string }>;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
isOwner: boolean;
|
can: {
|
||||||
|
update: boolean;
|
||||||
|
close: boolean;
|
||||||
|
};
|
||||||
messages: {
|
messages: {
|
||||||
data: Array<any>;
|
data: Array<any>;
|
||||||
next_page_url: string | null;
|
next_page_url: string | null;
|
||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const breadcrumbs = [
|
|
||||||
{
|
|
||||||
name: 'Dynamics',
|
|
||||||
href: route('dynamics.index'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.dynamic.name,
|
|
||||||
href: route('dynamics.show', props.dynamic.id),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: props.ledger.name,
|
|
||||||
href: route('dynamics.ledgers.show', {
|
|
||||||
dynamic: props.dynamic.id,
|
|
||||||
ledger: props.ledger.id,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// Lightbox Modal state
|
// Lightbox Modal state
|
||||||
const activeLightboxUrl = ref<string | null>(null);
|
const activeLightboxUrl = ref<string | null>(null);
|
||||||
@ -202,7 +188,7 @@ function isOwnerUser(userId: number): boolean {
|
|||||||
{{ ledger.rules }}
|
{{ ledger.rules }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isOwner" class="flex flex-col gap-2">
|
<div v-if="can.update" class="flex flex-col gap-2">
|
||||||
<InertiaLink
|
<InertiaLink
|
||||||
:href="route('dynamics.ledgers.predefined-mutations.index', [dynamic.id, ledger.id])"
|
:href="route('dynamics.ledgers.predefined-mutations.index', [dynamic.id, ledger.id])"
|
||||||
class="c-ledger-show__manage-btn"
|
class="c-ledger-show__manage-btn"
|
||||||
@ -284,7 +270,7 @@ function isOwnerUser(userId: number): boolean {
|
|||||||
:ledger-id="ledger.id"
|
:ledger-id="ledger.id"
|
||||||
:mutations="ledger.mutations"
|
:mutations="ledger.mutations"
|
||||||
:participants="dynamic.participants"
|
:participants="dynamic.participants"
|
||||||
:is-owner="isOwner"
|
:can-update="can.update"
|
||||||
:ledger-alignment="ledger.alignment"
|
:ledger-alignment="ledger.alignment"
|
||||||
@open-lightbox="openLightbox"
|
@open-lightbox="openLightbox"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user