Skip to main content
Sign in
Snippets Groups Projects
Commit aae3622e authored by Emmanuel Raviart's avatar Emmanuel Raviart
Browse files

Differentiate id and name of persons.

parent b34ca02c
Branches
Tags
No related merge requests found
/// <reference types="@sveltejs/kit" /> /// <reference types="@sveltejs/kit" />
/// <reference types="svelte" /> /// <reference types="svelte" />
/// <reference types="vite/client" /> /// <reference types="vite/client" />
// See: https://github.com/isaacHagoel/svelte-dnd-action#typescript
// Needed until following bug is solved:
// https://github.com/sveltejs/language-tools/issues/431.
declare type DndEvent = import("svelte-dnd-action").DndEvent
declare namespace svelte.JSX {
interface HTMLAttributes<T> {
onconsider?: (
event: CustomEvent<DndEvent> & { target: EventTarget & T },
) => void
onfinalize?: (
event: CustomEvent<DndEvent> & { target: EventTarget & T },
) => void
}
}
...@@ -3,52 +3,72 @@ ...@@ -3,52 +3,72 @@
import { flip } from "svelte/animate" import { flip } from "svelte/animate"
import { dndzone } from "svelte-dnd-action" import { dndzone } from "svelte-dnd-action"
import type { PersonSituation } from "$lib/situations"
export let idPrefix: string export let idPrefix: string
export let names: string[] | undefined | null export let personById: { [id: string]: PersonSituation }
export let personsId: string[] | undefined | null
export let type: string export let type: string
interface Item {
id: string
personId: string
}
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const existingItemByName = {} const existingItemByPersonId = {}
let existingItems = [] let existingItems = []
let existingNames = [] let existingPersonsId = []
const flipDurationMs = 300 const flipDurationMs = 300
$: items = computeItems(names) $: items = computeItems(personsId)
/// Create items from names, but try to reuse existing items when possible. /// Create items from names, but try to reuse existing items when possible.
/// Otherwise, svelte-dnd-action fails. /// Otherwise, svelte-dnd-action fails.
function computeItems(names: string[] | undefined | null) { function computeItems(personsId: string[] | undefined | null): Item[] {
if (names == null) { if (personsId == null) {
return [] return []
} }
if ( if (
names.length === existingNames.length && personsId.length === existingPersonsId.length &&
names.every((name, index) => name === existingNames[index]) personsId.every((id, index) => id === existingPersonsId[index])
) { ) {
return existingItems return existingItems
} }
const items = names.map((name) => { const items = personsId.map((id) => {
let item = existingItemByName[name] let item = existingItemByPersonId[id]
if (item === undefined) { if (item === undefined) {
item = existingItemByName[name] = { id: `${idPrefix}.${name}`, name } item = existingItemByPersonId[id] = {
id: `${idPrefix}.${id}`,
personId: id,
}
} }
return item return item
}) })
existingNames = names existingPersonsId = personsId
existingItems = items existingItems = items
return items return items
} }
function handleDndConsider({ detail }: CustomEvent<DndEvent>) { function handleDndConsider({ detail }: CustomEvent<DndEvent>) {
existingItems = detail.items existingItems = detail.items
existingNames = detail.items.map((item) => item.name) existingPersonsId = detail.items.map((item) => item.personId)
dispatch("change", existingNames) dispatch("change", existingPersonsId)
} }
function handleDndFinalize({ detail }: CustomEvent<DndEvent>) { function handleDndFinalize({ detail }: CustomEvent<DndEvent>) {
existingItems = detail.items existingItems = detail.items
existingNames = detail.items.map((item) => item.name) existingPersonsId = detail.items.map((item) => item.personId)
dispatch("change", existingNames) dispatch("change", existingPersonsId)
}
function* iterItemIdAndPersonCouples(
personById: { [id: string]: PersonSituation },
items: Item[],
): Generator<{ id: string; person: PersonSituation }, void, unknown> {
for (const { id, personId } of items) {
yield { id, person: personById[personId] }
}
} }
</script> </script>
...@@ -62,7 +82,9 @@ ...@@ -62,7 +82,9 @@
type, type,
}} }}
> >
{#each items as { id, name } (id)} {#each [...iterItemIdAndPersonCouples(personById, items)] as { id, person } (id)}
<li animate:flip={{ duration: flipDurationMs }} class="ml-4">{name}</li> <li animate:flip={{ duration: flipDurationMs }} class="ml-4">
{person.name ?? person.id}
</li>
{/each} {/each}
</ul> </ul>
<script lang="ts"> <script lang="ts">
import type { EntityByKey, Person, Group } from "@openfisca/ast" import type { EntityByKey, Group, Person, Role } from "@openfisca/ast"
import { session } from "$app/stores" import { session } from "$app/stores"
import type { Situation } from "$lib/situations" import RolePersonsEdit from "$lib/components/situations/RolePersonsEdit.svelte"
import type { PersonSituationWithoutId, Situation } from "$lib/situations"
export let situation: Situation export let situation: Situation
const flipDurationMs = 300
$: entityByKey = $session.entityByKey as EntityByKey $: entityByKey = $session.entityByKey as EntityByKey
$: personEntityKey = $session.personEntityKey as string $: personEntityKey = $session.personEntityKey as string
$: personEntity = entityByKey[personEntityKey] as Person $: personEntity = entityByKey[personEntityKey] as Person
$: personByName = situation[personEntity.key_plural] ?? {} $: persons = Object.entries(
(situation[personEntity.key_plural] ?? {}) as {
[id: string]: PersonSituationWithoutId
},
).map(([personId, person]) => ({
...person,
id: personId,
}))
$: personById = Object.fromEntries(
persons.map((person) => [person.id, person]),
)
function addEntityInstance(key: string): void { function addEntityInstance(key: string): void {
const entity = entityByKey[key] const entity = entityByKey[key]
const entityInstanceName = `${entity.label ?? entity.key} ${ const entityInstanceId = `${entity.label ?? entity.key} ${
Object.keys(situation[entity.key_plural]).length + 1 Object.keys(situation[entity.key_plural]).length + 1
}` }`
const entityInstanceByName = { const entityInstanceById = {
...situation[entity.key_plural], ...situation[entity.key_plural],
[entityInstanceName]: {}, [entityInstanceId]: {},
} }
situation = { ...situation, [entity.key_plural]: entityInstanceByName } situation = { ...situation, [entity.key_plural]: entityInstanceById }
if (entity.is_person) { if (entity.is_person) {
for (const group of Object.values(entityByKey) as Group[]) { for (const groupEntity of Object.values(entityByKey) as Group[]) {
if (group.is_person) { if (groupEntity.is_person) {
continue continue
} }
const groupInstanceByName: const groupById:
| { [name: string]: { [roleKeyPlural: string]: string[] } } | { [id: string]: { [roleKeyPlural: string]: string[] } }
| undefined = situation[group.key_plural] | undefined = situation[groupEntity.key_plural]
if (groupInstanceByName === undefined) { if (groupById === undefined) {
continue continue
} }
const groupInstanceNameAndInstanceCouples = const idAndGroupCouples = Object.entries(groupById)
Object.entries(groupInstanceByName) if (idAndGroupCouples.length === 0) {
if (groupInstanceNameAndInstanceCouples.length === 0) {
continue continue
} }
const [lastGroupInstanceName, lastGroupInstance] = const [lastGroupId, lastGroup] =
groupInstanceNameAndInstanceCouples[ idAndGroupCouples[idAndGroupCouples.length - 1]
groupInstanceNameAndInstanceCouples.length - 1
]
let foundRoleIndex: number = 0 let foundRoleIndex: number = 0
for (const [roleIndex, role] of [...group.roles.entries()].reverse()) { for (const [roleIndex, role] of [
...groupEntity.roles.entries(),
].reverse()) {
const roleKey = const roleKey =
role.max === undefined || role.max > 1 ? role.key_plural : role.key role.max === undefined || role.max > 1 ? role.key_plural : role.key
const rolePersonsName = lastGroupInstance[roleKey] const rolePersonsId = lastGroup[roleKey]
if (rolePersonsName !== undefined && rolePersonsName.length > 0) { if (rolePersonsId !== undefined && rolePersonsId.length > 0) {
foundRoleIndex = roleIndex foundRoleIndex = roleIndex
break break
} }
} }
let completedRolePersonsName: string[] | undefined = undefined let completedRolePersonsId: string[] | undefined = undefined
for (; foundRoleIndex < group.roles.length; foundRoleIndex++) { for (; foundRoleIndex < groupEntity.roles.length; foundRoleIndex++) {
const role = group.roles[foundRoleIndex] const role = groupEntity.roles[foundRoleIndex]
const roleKey = const roleKey =
role.max === undefined || role.max > 1 ? role.key_plural : role.key role.max === undefined || role.max > 1 ? role.key_plural : role.key
const rolePersonsName = lastGroupInstance[roleKey] const rolePersonsId = lastGroup[roleKey]
if (rolePersonsName === undefined) { if (rolePersonsId === undefined) {
completedRolePersonsName = [entityInstanceName] completedRolePersonsId = [entityInstanceId]
break break
} }
if (role.max === undefined || rolePersonsName.length < role.max) { if (role.max === undefined || rolePersonsId.length < role.max) {
completedRolePersonsName = [...rolePersonsName, entityInstanceName] completedRolePersonsId = [...rolePersonsId, entityInstanceId]
break break
} }
} }
if (completedRolePersonsName !== undefined) { if (completedRolePersonsId !== undefined) {
const role = group.roles[foundRoleIndex] const role = groupEntity.roles[foundRoleIndex]
const roleKey = const roleKey =
role.max === undefined || role.max > 1 ? role.key_plural : role.key role.max === undefined || role.max > 1 ? role.key_plural : role.key
situation[group.key_plural] = { situation[groupEntity.key_plural] = {
...groupInstanceByName, ...groupById,
[lastGroupInstanceName]: { [lastGroupId]: {
...lastGroupInstance, ...lastGroup,
[roleKey]: completedRolePersonsName, [roleKey]: completedRolePersonsId,
}, },
} }
} }
} }
} }
} }
function changeRolePersonsId(
groupEntityKeyUsed: string,
groupId: string,
roleKeyUsed: string,
personsId: string[],
): void {
situation = {
...situation,
[groupEntityKeyUsed]: {
...situation[groupEntityKeyUsed],
[groupId]: {
...situation[groupEntityKeyUsed][groupId],
[roleKeyUsed]: personsId,
},
},
}
}
function* iterGroupEntities(
entityByKey: EntityByKey,
): Generator<Group, void, unknown> {
for (const group of Object.values(entityByKey)) {
if (!group.is_person) {
yield group as Group
}
}
}
</script> </script>
<section> <section>
<h1>{personEntity.label_plural ?? personEntity.key_plural}</h1> <h1>{personEntity.label_plural ?? personEntity.key_plural}</h1>
<ol> <dl>
{#each Object.entries(personByName) as [personName, person], index (`${personEntity.key_plural}.${index}`)} {#each persons as person, index (`${personEntity.key_plural}.${index}`)}
<li> <dt>{person.name ?? person.id}</dt>
{personName} <dd><pre>{JSON.stringify(person, null, 2)}</pre></dd>
<pre>{JSON.stringify(person, null, 2)}</pre>
</li>
{/each} {/each}
</ol> </dl>
<button <button
class="bg-le-bleu hover:bg-blue-900 p-1 rounded shadow-md text-white" class="bg-le-bleu hover:bg-blue-900 p-1 rounded shadow-md text-white"
on:click={() => addEntityInstance(personEntityKey)} on:click={() => addEntityInstance(personEntityKey)}
...@@ -104,21 +143,53 @@ ...@@ -104,21 +143,53 @@
> >
</section> </section>
{#each Object.values(entityByKey) as entity} {#each [...iterGroupEntities(entityByKey)] as groupEntity}
{#if !entity.is_person} {#if !groupEntity.is_person}
<section> <section>
<h1>{entity.label_plural ?? entity.key_plural}</h1> <h1 class="font-bold my-4 text-xl">
<ol> {groupEntity.label_plural ?? groupEntity.key_plural}
{#each Object.entries(situation[entity.key_plural] ?? {}) as [name, instance], index (`${entity.key_plural}.${index}`)} </h1>
<li> <dl>
{name} {#each Object.entries(situation[groupEntity.key_plural] ?? {}) as [groupId, group], index (`${groupEntity.key_plural}.${index}`)}
<pre>{JSON.stringify(instance, null, 2)}</pre> <dt>{groupId}</dt>
</li> <dd class="ml-4">
<dl>
{#each groupEntity.roles as role}
<dt>
{role.max === undefined || role.max > 1
? role.label_plural ?? role.key_plural
: role.label ?? role.key}
</dt>
<dd class="ml-4">
<RolePersonsEdit
idPrefix="{groupEntity.key_plural}.{groupId}.{role.key}"
{personById}
personsId={group[
role.max === undefined || role.max > 1
? role.key_plural
: role.key
]}
on:change={({ detail }) =>
changeRolePersonsId(
groupEntity.key_plural,
groupId,
role.max === undefined || role.max > 1
? role.key_plural
: role.key,
detail,
)}
type={groupEntity.key_plural}
/>
</dd>
{/each}
</dl>
<pre>{JSON.stringify(group, null, 2)}</pre>
</dd>
{/each} {/each}
</ol> </dl>
<button <button
class="bg-le-bleu hover:bg-blue-900 p-1 rounded shadow-md text-white" class="bg-le-bleu hover:bg-blue-900 p-1 rounded shadow-md text-white"
on:click={() => addEntityInstance(entity.key)} on:click={() => addEntityInstance(groupEntity.key)}
type="button">+</button type="button">+</button
> >
</section> </section>
... ...
......
...@@ -8,31 +8,44 @@ export interface Axis { ...@@ -8,31 +8,44 @@ export interface Axis {
} }
export interface EntitySituation { export interface EntitySituation {
[key: string]: { [date: string]: number | null } | string[] [key: string]: { [date: string]: number | null } | string | string[]
} }
export interface EntitySituationComplement { export interface EntitySituationComplement {
[key: string]: boolean | number | string | null [key: string]: boolean | number | string | null
} }
// TODO: Obsolete
export interface FamilleSituation extends EntitySituation { export interface FamilleSituation extends EntitySituation {
enfants: string[] enfants: string[]
parents: string[] parents: string[]
} }
// TODO: Obsolete
export interface FoyerFiscalSituation extends EntitySituation { export interface FoyerFiscalSituation extends EntitySituation {
declarants: string[] declarants: string[]
personnes_a_charge: string[] personnes_a_charge: string[]
} }
// TODO: Obsolete
export type IndividuSituation = EntitySituation export type IndividuSituation = EntitySituation
// TODO: Obsolete
export interface MenageSituation extends EntitySituation { export interface MenageSituation extends EntitySituation {
conjoint: string[] conjoint: string[]
enfants: string[] enfants: string[]
personne_de_reference: string[] personne_de_reference: string[]
} }
export interface PersonSituation extends PersonSituationWithoutId {
id: string
}
export interface PersonSituationWithoutId extends EntitySituation {
name?: string
}
// TODO: Obsolete
export interface Situation { export interface Situation {
axes?: Axis[][] axes?: Axis[][]
familles: { [name: string]: FamilleSituation } familles: { [name: string]: FamilleSituation }
... ...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment