132 lines
4.6 KiB
Vue
132 lines
4.6 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
AccordionContent,
|
|
} from '@/components/ui/accordion';
|
|
import { useDebounceFn } from '@vueuse/core';
|
|
import { toast } from 'vue-sonner';
|
|
import { deleteUserWarren } from '~/lib/api/admin/deleteUserWarren';
|
|
import { editUserWarren } from '~/lib/api/admin/editUserWarren';
|
|
import type { UserWarren } from '~/shared/types/warrens';
|
|
|
|
const props = defineProps<{
|
|
userWarren: UserWarren;
|
|
}>();
|
|
let realUserWarrenState: UserWarren = JSON.parse(
|
|
JSON.stringify(props.userWarren)
|
|
);
|
|
const userWarren = props.userWarren;
|
|
|
|
const adminStore = useAdminStore();
|
|
|
|
const updatePermissionsDebounced = useDebounceFn(
|
|
async (uw: UserWarren) => {
|
|
const result = await editUserWarren(uw);
|
|
|
|
if (result.success) {
|
|
for (const [key, value] of Object.entries(result.data)) {
|
|
if (key in userWarren) {
|
|
// @ts-expect-error Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
|
|
userWarren[key] = value;
|
|
}
|
|
}
|
|
realUserWarrenState = JSON.parse(JSON.stringify(result.data));
|
|
toast.success('Permissions', {
|
|
description: `Successfully updated the user's permissions`,
|
|
});
|
|
} else {
|
|
for (const [key, value] of Object.entries(realUserWarrenState)) {
|
|
if (key in userWarren) {
|
|
// @ts-expect-error Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
|
|
userWarren[key] = value;
|
|
}
|
|
}
|
|
userWarren.canCreateShares = realUserWarrenState.canCreateShares;
|
|
|
|
toast.error('Permissions', {
|
|
description: `Failed to update the user's permissions`,
|
|
});
|
|
}
|
|
},
|
|
1000,
|
|
{ maxWait: 5000 }
|
|
);
|
|
|
|
function permissionChanged(userWarren: UserWarren) {
|
|
updatePermissionsDebounced(userWarren);
|
|
}
|
|
|
|
async function onDeleteClicked() {
|
|
const { success } = await deleteUserWarren(
|
|
userWarren.userId,
|
|
userWarren.warrenId
|
|
);
|
|
if (!success) {
|
|
return;
|
|
}
|
|
|
|
if (adminStore.editUserDialog != null) {
|
|
// TODO: remove
|
|
/* adminStore.editUserDialog.user.warrens =
|
|
adminStore.editUserDialog.user.warrens.filter(
|
|
(uw) =>
|
|
uw.userId !== userWarren.userId ||
|
|
uw.warrenId != userWarren.warrenId
|
|
); */
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<AccordionItem
|
|
:value="userWarren.warrenId"
|
|
class="bg-accent/30 group/user-warren w-full justify-start rounded-md"
|
|
>
|
|
<AccordionTrigger class="items-center px-4">
|
|
<div class="flex w-full flex-row justify-between">
|
|
<div
|
|
class="flex w-full flex-col gap-0 overflow-hidden text-left leading-4"
|
|
>
|
|
<span class="font-medium !no-underline">{{
|
|
adminStore.resources.warrens[userWarren.warrenId]?.name
|
|
}}</span>
|
|
<span class="text-muted-foreground text-xs">{{
|
|
adminStore.resources.warrens[userWarren.warrenId]?.path
|
|
}}</span>
|
|
</div>
|
|
<Button
|
|
class="transition-all not-pointer-coarse:opacity-0 not-pointer-coarse:group-hover/user-warren:opacity-100"
|
|
variant="destructive"
|
|
size="icon"
|
|
@click="onDeleteClicked"
|
|
>
|
|
<Icon name="lucide:trash-2" />
|
|
</Button>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent class="px-4">
|
|
<div class="grid w-full grid-cols-1 gap-4 pt-1 sm:grid-cols-2">
|
|
<div
|
|
v-for="[permissionKey] in getUserWarrenPermissions(
|
|
userWarren
|
|
)"
|
|
:key="permissionKey"
|
|
class="flex w-full flex-row items-center justify-between"
|
|
>
|
|
<Label :for="permissionKey" class="grow">{{
|
|
getUserWarrenPermissionName(permissionKey)
|
|
}}</Label>
|
|
<Switch
|
|
:id="permissionKey"
|
|
v-model="userWarren[permissionKey]"
|
|
@update:model-value="
|
|
() => permissionChanged(userWarren)
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</template>
|