Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vac items: PC-727 (toevoegen) en PC-729 (bewerken) #1010

Merged
merged 15 commits into from
Jan 16, 2025
Merged
6 changes: 5 additions & 1 deletion Kiss.Bff/Config/AuthenticationSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ public static IServiceCollection AddKissAuth(this IServiceCollection services, A
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.SlidingExpiration = true;
//options.Events.OnSigningOut = (e) => e.HttpContext.RevokeRefreshTokenAsync();
options.Events.OnRedirectToAccessDenied = HandleLoggedOut;
options.Events.OnRedirectToAccessDenied = (ctx) =>
{
ctx.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
};
options.Events.OnRedirectToLogin = HandleLoggedOut;
});

Expand Down
39 changes: 39 additions & 0 deletions Kiss.Bff/Extern/Vacs/PostVacsCustomProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Kiss.Bff.Vacs
{
[ApiController]
public class PostVacsCustomProxy : ControllerBase
{
private readonly VacsProxyConfig _config;

public PostVacsCustomProxy(VacsProxyConfig config)
{
_config = config;
}

[HttpPost]
[Authorize(Policy = Policies.RedactiePolicy)]
[Route("api/vacs/api/{version}/objects")]
mstokericatt marked this conversation as resolved.
Show resolved Hide resolved
public IActionResult Post([FromRoute] string version, [FromBody] JsonObject node)
{
node["type"] = _config.ObjectTypeUrl;

if (node.TryGetPropertyValue("record", out var record) && record is JsonObject recordObj)
{
recordObj["typeVersion"] = _config.TypeVersion;
}

var url = $"{_config.Destination.TrimEnd('/')}/api/{version}/objects";

return new ProxyResult(() =>
{
var request = new HttpRequestMessage(HttpMethod.Post, url) { Content = JsonContent.Create(node) };
_config.ApplyHeaders(request.Headers);
return request;
});
}
}
}
5 changes: 3 additions & 2 deletions Kiss.Bff/Extern/Vacs/VacsProxyConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ public static class VacsExtensions
{
public static IServiceCollection AddVacsProxy(this IServiceCollection services, string destination, string token, string objectTypeUrl, string typeVersion)
{
return services.AddSingleton<IKissProxyRoute>(s =>
return services.AddSingleton(s =>
mstokericatt marked this conversation as resolved.
Show resolved Hide resolved
{
var authorizationService = s.GetRequiredService<IAuthorizationService>();
var policyProvider = s.GetRequiredService<IAuthorizationPolicyProvider>();

return new VacsProxyConfig(destination, token, objectTypeUrl, typeVersion, authorizationService, policyProvider);
});
})
.AddSingleton<IKissProxyRoute>(s => s.GetRequiredService<VacsProxyConfig>());
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/components/ckeditor/CkEditorAsync.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ const config: EditorConfig = {
"blockQuote",
"undo",
"redo",
"insertTable",
],
table: {
defaultHeadings: { rows: 1 },
contentToolbar: ["tableColumn", "tableRow"],
},
};
</script>

Expand Down
2 changes: 2 additions & 0 deletions src/components/ckeditor/ckeditor-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export {
Link,
List,
Paragraph,
Table,
TableToolbar,
type EditorConfig,
} from "ckeditor5";

Expand Down
4 changes: 4 additions & 0 deletions src/features/search/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ export type Vac = {
uuid?: string;
vraag: string;
antwoord: string;
toelichting?: string;
afdelingen?: VacAfdeling[];
trefwoorden?: { trefwoord: string }[];
status?: string;
doelgroep?: string;
};

export type Nieuwsbericht = {
Expand Down
251 changes: 237 additions & 14 deletions src/views/Beheer/vacs/VacBeheer.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,243 @@
<template>
<utrecht-heading :level="1">{{ uuid }}</utrecht-heading>

<menu>
<li>
<router-link
to="/Beheer/vacs/"
class="utrecht-button utrecht-button--secondary-action"
>
Annuleren
</router-link>
</li>
</menu>
<utrecht-heading :level="1"
>Vac {{ props.uuid ? "bewerken" : "toevoegen" }}</utrecht-heading
>

<simple-spinner v-if="loading" />

<p v-else-if="error">Er is een fout opgetreden bij het ophalen van de Vac.</p>

<beheer-form @submit="submit" v-else>
<template #formFields>
<label class="utrecht-form-label"
><span>Vraag *</span>

<input
class="utrecht-textbox utrecht-textbox--html-input"
type="text"
v-model="vac.record.data.vraag"
required
/></label>

<label class="utrecht-form-label" for="antwoord">Antwoord *</label>
<ck-editor v-model="vac.record.data.antwoord" required />

<label class="utrecht-form-label" for="toelichting">Toelichting</label>
<ck-editor v-model="vac.record.data.toelichting" />

<fieldset>
<legend>Afdelingen</legend>

<ul>
<li
v-for="(value, key) in vac.record.data.afdelingen"
:key="`afdeling_${key}`"
>
<label class="utrecht-form-label">
<input
class="utrecht-textbox utrecht-textbox--html-input"
type="text"
v-model="value.afdelingNaam"
:aria-label="`Afdeling ${key + 1}`"
/></label>
</li>
</ul>
</fieldset>

<fieldset>
<legend>Trefwoorden</legend>

<ul>
<li
v-for="(value, key) in vac.record.data.trefwoorden"
:key="`trefwoord_${key}`"
>
<label class="utrecht-form-label">
<input
class="utrecht-textbox utrecht-textbox--html-input"
type="text"
v-model="value.trefwoord"
:aria-label="`Trefwoord ${key + 1}`"
/></label>
</li>
</ul>
</fieldset>

<p>Velden met (*) zijn verplicht</p>
</template>

<template #formMenuListItems>
<li>
<router-link
to="/Beheer/vacs/"
class="utrecht-button utrecht-button--secondary-action"
>
Annuleren
</router-link>
</li>

<li>
<utrecht-button appearance="primary-action-button" type="submit">
Opslaan
</utrecht-button>
</li>
</template>
</beheer-form>
</template>

<script setup lang="ts">
import { Heading as UtrechtHeading } from "@utrecht/component-library-vue";
import { onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import {
Heading as UtrechtHeading,
Button as UtrechtButton,
} from "@utrecht/component-library-vue";
import SimpleSpinner from "@/components/SimpleSpinner.vue";
import CkEditor from "@/components/ckeditor";
import BeheerForm from "@/components/beheer/BeheerForm.vue";
import { fetchLoggedIn, parseJson, throwIfNotOk } from "@/services";
import type { Vac } from "@/features/search/types";
import { toast } from "@/stores/toast";

type VacObject = {
record: {
startAt: string;
data: Vac;
index?: number;
correctionFor?: number;
};
};

const vacObjectenUrl = "/api/vacs/api/v2/objects";

const props = defineProps<{ uuid?: string }>();
const router = useRouter();

const loading = ref(false);
const error = ref(false);

defineProps<{ uuid?: string }>();
const afdelingen = Array.from({ length: 5 }, () => ({ afdelingNaam: "" }));
const trefwoorden = Array.from({ length: 10 }, () => ({ trefwoord: "" }));

const vac = ref<VacObject>({
record: {
startAt: new Date().toISOString().substring(0, 10),
data: {
vraag: "",
antwoord: "",
afdelingen,
toelichting: "",
trefwoorden,
},
},
});

// Update with fetched data while remaining array length
watch(
() => ({
afdelingData: vac.value.record.data.afdelingen,
trefwoordData: vac.value.record.data.trefwoorden,
}),
({ afdelingData, trefwoordData }) => {
vac.value.record.data.afdelingen = [
...(afdelingData || []),
...afdelingen,
].slice(0, afdelingen.length);

vac.value.record.data.trefwoorden = [
...(trefwoordData || []),
...trefwoorden,
].slice(0, trefwoorden.length);
},
{ once: true },
);

const showError = () => {
toast({
text: "Er is een fout opgetreden bij het opslaan van de Vac. Probeer het later opnieuw.",
type: "error",
});
};

const handleSuccess = () => {
toast({
text: "De Vac is opgeslagen.",
});

router.push("/Beheer/vacs");
};

const submit = async () => {
loading.value = true;

const createPayload = () => {
const body = {
...vac.value,
...{
record: {
...vac.value.record,
data: {
...vac.value.record.data,
afdelingen: vac.value.record.data.afdelingen?.filter(
(afdeling) => afdeling.afdelingNaam.trim().length,
),
trefwoorden: vac.value.record.data.trefwoorden?.filter(
(trefwoord) => trefwoord.trefwoord.trim().length,
),
status: "actief",
doelgroep: "eu-burger",
},
correctionFor: props.uuid ? vac.value.record.index : undefined,
},
},
};

return JSON.stringify(body);
};

const result = await fetchLoggedIn(
`${vacObjectenUrl}/${props.uuid ? props.uuid : ""}`,
{
method: props.uuid ? "PUT" : "POST",
headers: {
"Content-Type": "application/json",
},
body: createPayload(),
},
).finally(() => (loading.value = false));
mstokericatt marked this conversation as resolved.
Show resolved Hide resolved

result.ok ? handleSuccess() : showError();
};

onMounted(() => {
if (!props.uuid) return;

loading.value = true;

fetchLoggedIn(`${vacObjectenUrl}/${props.uuid}`)
.then(throwIfNotOk)
.then(parseJson)
.then((result: VacObject) => (vac.value = result))
.catch(() => (error.value = true))
.finally(() => (loading.value = false));
});
</script>

<style lang="scss" scoped>
fieldset {
legend {
color: var(--utrecht-form-label-color);
font-size: var(--utrecht-form-label-font-size);
font-weight: var(--utrecht-form-label-font-weight);
margin-block-end: var(--spacing-default);
}

ul {
display: flex;
flex-direction: column;
gap: var(--spacing-default);
list-style: disc;
padding-inline-start: var(--spacing-default);
}
}
</style>
15 changes: 13 additions & 2 deletions src/views/Beheer/vacs/VacsBeheer.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
<template>
<utrecht-heading :level="1">Vacs</utrecht-heading>
<div class="header-wrapper">
<utrecht-heading :level="1">Vacs</utrecht-heading>

<router-link
to="/Beheer/vac/"
title="Toevoegen"
class="utrecht-button utrecht-button--primary-action icon icon-after plus icon-only"
>
</router-link>
</div>

<simple-spinner v-if="loading" />

<div v-else-if="error">Er is een fout opgetreden.</div>
<div v-else-if="error">
mstokericatt marked this conversation as resolved.
Show resolved Hide resolved
Er is een fout opgetreden bij het ophalen van de Vacs.
</div>

<ul v-else>
<li v-for="vac in vacs" :key="vac.uuid" class="listItem">
Expand Down
Loading