Skip to content
Snippets Groups Projects
Unverified Commit 420d5f8b authored by Dorine Lambinet's avatar Dorine Lambinet
Browse files

Copie ancien composant pour les avoir en vue le temps de la refacto

parent f2a19a01
No related branches found
No related tags found
No related merge requests found
<script lang="ts">
import type { VariableByName } from "@openfisca/json-model"
import { goto } from "$app/navigation"
import OilSpendingBill from "$lib/components/impacts_view/test_cases_view/test_case_selected/OilSpendingBill.svelte"
import TestCaseGraph from "$lib/components/impacts_view/test_cases_view/test_case_selected/graph/TestCaseGraph.svelte"
import Tooltip from "$lib/components/ui_transverse_components/Tooltip.svelte"
import {
type VisibleDecomposition,
type EvaluationByName,
isChildOrDescendant,
} from "$lib/decompositions"
import { buildVisibleDecompositions } from "$lib/decompositions"
import type { DisplayMode } from "$lib/displays"
import { entityByKey, personEntityKey } from "$lib/entities"
import { trackTestCaseGraph } from "$lib/matomo"
import { revaluationName, shared } from "$lib/shared.svelte"
import {
type ActiveSlider,
getSituationVariableValue,
setSituationVariableValue,
type Situation,
} from "$lib/situations"
import { newSimulationUrl } from "$lib/urls"
import { removeNegativeZero } from "$lib/values"
import {
oilTypes,
type ValuesByCalculationNameByVariableName,
type VariableValue,
} from "$lib/variables"
import LinkedVariables from "$lib/components/impacts_view/test_cases_view/test_case_selected/LinkedVariables.svelte"
import { iterToDepth } from "$lib/iterators"
import StandardOfLiving from "$lib/components/impacts_view/test_cases_view/test_case_selected/StandardOfLiving.svelte"
interface Props {
displayMode: DisplayMode
evaluationByName: EvaluationByName
showLoader?: boolean
situation: Situation
situationIndex: number
valuesByCalculationNameByVariableName: ValuesByCalculationNameByVariableName
variableSummaryByName: VariableByName
year: number
}
let {
displayMode,
evaluationByName,
showLoader = true,
situation = $bindable(),
situationIndex,
valuesByCalculationNameByVariableName,
variableSummaryByName,
year,
}: Props = $props()
const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
.format
const deltaFormatter = (value: number): string =>
new Intl.NumberFormat("fr-FR", {
currency: "EUR",
maximumFractionDigits: 0,
minimumFractionDigits: 0,
signDisplay: "never",
style: "currency",
}).format(removeNegativeZero(value))
const firstDeltaFormatter = (value: number): string =>
new Intl.NumberFormat("fr-FR", {
currency: "EUR",
maximumFractionDigits: 0,
minimumFractionDigits: 0,
style: "currency",
}).format(removeNegativeZero(value))
const personEntity = entityByKey[personEntityKey]
const oilSpendings = oilTypes.map((name) => ({
depenseTtcVariableName: `depense_${name}_ttc`,
nombreLitresVariableName: `nombre_litres_${name}`,
// prixTtcLitreVariableName: `prix_${name}_hors_remise_ttc_sortie`,
prixTtcLitreVariableName: `prix_${name}_ttc`,
ticpeVariableName: `${name}_ticpe`,
tvaVariableName: `tva_sur_${name}`,
}))
let useRevaluationInsteadOfLaw = $derived(revaluationName !== undefined)
let firstCalculationName = $derived(
useRevaluationInsteadOfLaw ? "revaluation" : "law",
)
let runningCalculationNames = $derived(
Object.entries(shared.calculationByName)
.filter(([, calculation]) => calculation.running)
.map(([calculationName]) => calculationName),
)
let modificationsAmendmentCount = $derived(
Object.keys(shared.parametricReform).length,
)
let visibleDecompositions: VisibleDecomposition[] = $state([])
$effect(() => {
visibleDecompositions = buildVisibleDecompositions(
shared.decompositionByName,
entityByKey,
evaluationByName,
situation,
variableSummaryByName,
shared.waterfall,
shared.showNulls,
useRevaluationInsteadOfLaw,
shared.vectorLength,
year,
)
})
let personSituation = $derived(situation[personEntity.key_plural!])
function getCorrectSimulationUrl(variableName: string) {
const newDisplayMode =
displayMode.edit !== undefined
? {
...displayMode,
variableName: variableName,
}
: {
...displayMode,
mobileLaw: true,
parametersVariableName: variableName,
}
return newSimulationUrl(newDisplayMode)
}
function getFirstPersonActivity(personSituation) {
const populationId = Object.keys(personSituation).sort(
(populationId1, populationId2) =>
populationId1.localeCompare(populationId2),
)[0]
return getVariableValue(situation, "activite", populationId)
}
function getVariableValue(
situation: Situation,
variableName: string,
populationId: string,
): VariableValue | undefined {
const variable = variableSummaryByName[variableName]
if (variable === undefined) {
return undefined
}
return getSituationVariableValue(situation, variable, populationId, year)
}
function removeSituationSlider() {
if (shared.savedSituation !== undefined) {
situation = shared.savedSituation
delete shared.savedSituation
if (shared.savedSituationIndex !== undefined) {
shared.testCases[shared.savedSituationIndex] = situation
delete shared.savedSituationIndex
}
}
}
function requestAxesCalculation() {
// Ensure that situation of previous curve is not merged with the new one.
if (
shared.savedSituation !== undefined &&
shared.savedSituationIndex !== undefined
) {
shared.testCases[shared.savedSituationIndex] = shared.savedSituation
}
shared.savedSituation = situation
shared.savedSituationIndex = situationIndex
situation = structuredClone($state.snapshot(situation))
shared.testCases[situationIndex] = situation
if (
situation.sliders?.length === undefined ||
situation.sliders?.length <= 0
) {
console.error(
"requestAxesCalculation",
"Situation sliders list is undefined",
)
return
}
// Get situation
const variable = variableSummaryByName[situation.sliders?.[0].name]
const slider = situation.sliders.find(
(slider) =>
slider.entity === variable.entity && slider.name === variable.name,
) as ActiveSlider | undefined
if (slider === undefined) {
console.error("requestAxesCalculation", "Slider is undefined")
return
}
const updatedMin = slider.min
const updatedMax = slider.max
const updatedStepValue = (updatedMax - updatedMin) / 100 ?? slider.stepValue
const value = getSituationVariableValue(
situation,
variable,
slider.id,
year,
) as number
const vectorIndex = Math.max(
0,
Math.min(100, Math.round(value / updatedStepValue)),
)
// Update situation
setSituationVariableValue(
entityByKey,
situation,
variable,
slider.id,
year,
Math.round(updatedStepValue * vectorIndex),
)
situation.slider = {
...slider,
min: updatedMin,
max: updatedMax,
stepValue: updatedStepValue,
vectorIndex: vectorIndex,
}
}
function zoomIn(index: number) {
let visibleDecomposition = visibleDecompositions[index]
if (
visibleDecomposition === undefined ||
visibleDecomposition.visibleChildren === undefined
) {
return
}
let decomposition = visibleDecomposition.decomposition
if (!decomposition.open) {
shared.decompositionByName[decomposition.name] = {
...decomposition,
open: true,
}
return
}
}
function zoomOut(index: number) {
let visibleDecomposition = visibleDecompositions[index]
if (
visibleDecomposition === undefined ||
visibleDecomposition.visibleChildren === undefined
) {
return
}
let decomposition = visibleDecomposition.decomposition
if (decomposition.open) {
shared.decompositionByName[decomposition.name] = {
...decomposition,
open: false,
}
return
}
}
</script>
<!--Ce composant se découpe en 3 zones :
- ZONE 1 : FEUILLE DE PAIE
- ZONE 2 : VARIALBES COMPLÉMENTAIRES À LA FEUILLE DE PAIE
- ZONE 3 : TICKET DE CARBURANT & GRAPHIQUE DES CAS TYPES
-->
{#if visibleDecompositions.length > 0}
{@const firstPersonActivity = getFirstPersonActivity(personSituation)}
<!--ZONE 1 : FEUILLE DE PAIE -->
<!-- Bouton affichage des montants nuls -->
<div
class="mx-4 mb-3 flex justify-start"
id="situation_{situationIndex}_waterfall_showall"
>
<label class="inline-flex cursor-pointer items-center">
<input
type="checkbox"
value=""
class="peer sr-only"
bind:checked={shared.showNulls}
/>
<div
class="peer relative h-6 w-11 shrink-0 rounded-full bg-gray-400 after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-le-bleu peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-0"
></div>
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300"
>Montrer tous les dispositifs<span
class="hidden sm:inline-flex md:hidden lg:inline-flex"
>, y compris si leur montant est à 0€</span
></span
>
</label>
</div>
<!-- Feuille de paie-->
<div class="flex justify-between">
<div class="w-3/5 flex-auto">
{#each visibleDecompositions as { decomposition, depth, rows, trunk, visibleChildren }, index}
<!-- Ligne de la feuille de paie-->
<div
class="flex min-h-8 items-stretch justify-between border-t border-gray-200 px-4"
class:bg-gray-100={trunk && index !== 0}
class:border-gray-300={trunk && index !== 0}
class:fond={decomposition.name ===
displayMode.parametersVariableName ||
(displayMode.parametersVariableName &&
isChildOrDescendant(
shared.decompositionByName,
decomposition.name,
displayMode.parametersVariableName,
))}
class:text-lg={decomposition.name ===
displayMode.parametersVariableName}
class:items-start={decomposition.name ===
displayMode.parametersVariableName}
>
<!-- Colonne 1 "Nom du dispositif"-->
<div class="flex-1 overflow-x-hidden">
{#each rows as { calculationName }}
{#if calculationName === firstCalculationName}
<div class="flex h-full w-full items-center">
<!--Si c'est une variable de type tronc, exemple : Rémunération brute -->
{#if trunk && index !== 0}
<!--Les class permettent que le nom de la variable soit caché avec "..." et rendu visible au survol. Le comportement est différent si la variable est sélectionnée-->
<div
class="flex w-full items-center"
class:whitespace-nowrap={decomposition.name !==
displayMode.parametersVariableName}
>
<!-- Nom de la variable tronc, cliquable -->
<a
class="cursor-pointer overflow-x-hidden text-ellipsis text-gray-500 hover:z-20 hover:overflow-x-visible hover:bg-white hover:bg-opacity-90 hover:pr-1 hover:text-le-gris-dispositif-dark hover:underline"
class:font-bold={decomposition.name ===
displayMode.parametersVariableName}
class:hover:absolute={decomposition.name !==
displayMode.parametersVariableName}
href={getCorrectSimulationUrl(decomposition.name)}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
</div>
{:else if visibleChildren === undefined}
<!--Si c'est une variable Non-trunk, leaf-variable : La variable n'a pas de variables enfants et elle n'est pas une variable tronc -->
<div
class="flex h-full w-full items-center"
class:whitespace-nowrap={decomposition.name !==
displayMode.parametersVariableName}
>
<!--Indentation pour chaque niveau de l'arbre, illustré par une bordure-->
{#each iterToDepth(depth)}
<div
class={`min-h-full border-l-2 bg-white pr-3 ${
decomposition.name !==
displayMode.parametersVariableName &&
!(
displayMode.parametersVariableName &&
isChildOrDescendant(
shared.decompositionByName,
decomposition.name,
displayMode.parametersVariableName,
)
)
? "border-gray-400"
: "border-black"
}`}
></div>
{/each}
<!--Si la variable est obsolète, ou que sa date de relecture est inconnue ou trop ancienne, un picto attention est affiché -->
{#if decomposition.obsolete || decomposition.last_value_still_valid_on === undefined || decomposition.last_value_still_valid_on < (new Date().getFullYear() - 2).toString()}
<Tooltip
allowFlip={false}
arrowClass="bg-gray-100"
widthClass="w-80"
initialPlacement="bottom"
>
<iconify-icon
class="mr-0.5 shadow-none {decomposition.obsolete
? 'text-[#FF4133]'
: 'text-[#FFAC33]'}"
icon="material-symbols:warning-rounded"
width="16"
height="16"
></iconify-icon>
{#snippet tooltip()}
<div
class="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl"
>
<div
class="border-b border-gray-200 bg-gray-100 px-3 py-2"
>
<h3 class="font-semibold text-gray-900">
⚠️ Ce dispositif n'est peut-être pas à jour
</h3>
</div>
<div
class="px-3 py-2 text-sm font-light text-gray-500"
>
Dernière relecture :
{#if decomposition.last_value_still_valid_on === undefined}
date indéterminée
{:else}{dateFormatter(
new Date(
decomposition.last_value_still_valid_on,
),
)}
{/if}
{#if decomposition.obsolete}
; Obsolète !{/if}
</div>
</div>
{/snippet}
</Tooltip>
{/if}
<!-- Nom de la variable non-trunk, leaf, cliquable -->
<a
class="cursor-pointer overflow-x-hidden text-ellipsis font-serif hover:z-20 hover:overflow-x-visible hover:bg-white hover:bg-opacity-90 hover:pr-1 hover:text-le-gris-dispositif-dark hover:underline"
class:font-bold={decomposition.name ===
displayMode.parametersVariableName}
class:hover:text-wrap={decomposition.name !==
displayMode.parametersVariableName}
href={getCorrectSimulationUrl(decomposition.name)}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
</div>
{:else}
<!-- Si c'est une variable Non-trunk, Non-leaf : La variable a des variables enfants et n'est pas une variable tronc | une flèche à droite permet d'ouvrir les variables enfants-->
<div
class="flex h-full w-full items-center justify-start"
class:whitespace-nowrap={decomposition.name !==
displayMode.parametersVariableName}
>
<!--Indentation pour chaque niveau de l'arbre, illustré par une bordure-->
{#each iterToDepth(depth)}
<div
class={`min-h-full border-l-2 bg-white pr-3 ${
decomposition.name !==
displayMode.parametersVariableName &&
!(
displayMode.parametersVariableName &&
isChildOrDescendant(
shared.decompositionByName,
decomposition.name,
displayMode.parametersVariableName,
)
)
? "border-gray-400"
: "border-black"
}`}
></div>
{/each}
<button
class="cursor-pointer overflow-x-hidden text-ellipsis text-left font-serif hover:z-20 hover:overflow-x-visible hover:bg-white hover:bg-opacity-90 hover:text-le-gris-dispositif-dark hover:underline"
class:hover:text-wrap={decomposition.name !==
displayMode.parametersVariableName}
class:font-bold={decomposition.name ===
displayMode.parametersVariableName}
onclick={() => {
// Non-leaf decomposition node in variable inputs mode => no-link
if (decomposition.open) {
zoomOut(index)
} else {
zoomIn(index)
}
// Leaf decomposition node with parameters in parameters mode => link
if (displayMode.edit === undefined) {
goto(getCorrectSimulationUrl(decomposition.name), {
noScroll: true,
})
}
}}
data-sveltekit-noscroll
>{decomposition.short_label ??
decomposition.label}</button
>
<button
class="text-black"
aria-label={decomposition.open
? "Ouvrir variables enfants"
: "Fermer"}
onclick={() =>
decomposition.open ? zoomOut(index) : zoomIn(index)}
>
<iconify-icon
class="align-[-0.25rem] text-lg hover:text-le-gris-dispositif"
icon={decomposition.open
? "ri-arrow-down-s-line"
: "ri-arrow-right-s-line"}
></iconify-icon>
</button>
</div>
{/if}
</div>
{/if}
{/each}
</div>
<!-- Colonne 2 - Valeur du dispositif-->
<div
class="flex flex-nowrap pr-1 sm:items-center md:pr-4"
class:py-1={!trunk}
class:items-end={!trunk}
>
<div class="flex flex-col justify-end sm:flex-row sm:items-center">
{#each rows as { calculationName, deltaAtVectorIndex }}
<span
class="h-full pl-1 text-right text-sm"
class:content-center={trunk}
class:content-start={!trunk}
>
<!--Loader squelette pendant que la valeur charge -->
{#if showLoader && runningCalculationNames.length > 0}
{#if runningCalculationNames.includes("law") || runningCalculationNames.includes("revaluation")}
<span
class="animate-pulse-2 bg-gray-500 px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("bill")}
<span
class="animate-pulse-2 bg-le-rouge-bill px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("amendment") && modificationsAmendmentCount > 0}
<span
class="animate-pulse-2 bg-le-jaune px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
<!--Valeur du waterfall-->
{:else if trunk && index !== 0}
<span
class=" {calculationName === firstCalculationName
? rows.find((row) => row.calculationName === 'bill') ===
undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-gray-500'
: 'text-gray-500 line-through-amendment'
: 'text-gray-500 line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune text-gray-500'}"
class:text-base={decomposition.name !==
displayMode.parametersVariableName}
class:text-2xl={decomposition.name ===
displayMode.parametersVariableName}
class:font-bold={decomposition.name ===
displayMode.parametersVariableName}
><span
class="content-center pr-1 font-normal text-gray-500"
>=</span
>{firstDeltaFormatter(deltaAtVectorIndex ?? 0)}</span
>
{:else}
<span
class="font-bold {calculationName === firstCalculationName
? rows.find((row) => row.calculationName === 'bill') ===
undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? ''
: 'line-through-amendment'
: 'line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
class:opacity-20={decomposition.open}
class:text-base={decomposition.name !==
displayMode.parametersVariableName}
class:text-3xl={decomposition.name ===
displayMode.parametersVariableName}
class:font-semibold={decomposition.name ===
displayMode.parametersVariableName}
>{#if index !== 0}{#if deltaAtVectorIndex < 0}-{:else if deltaAtVectorIndex > 0}+{/if}{/if}
{deltaFormatter(deltaAtVectorIndex ?? 0)}</span
>
{/if}
</span>
{/each}
</div>
</div>
</div>
<!--Affichage des variables liées s'il y en a-->
{#if displayMode.parametersVariableName !== undefined && decomposition.name === displayMode.parametersVariableName}
<LinkedVariables
{displayMode}
{evaluationByName}
{situationIndex}
{variableSummaryByName}
{decomposition}
{depth}
{visibleChildren}
/>
{/if}
{/each}
</div>
</div>
<!--AJout de la variable niveau de vie-->
{#if shared.waterfall.name === "brut_to_disponible"}
<StandardOfLiving {situation} {valuesByCalculationNameByVariableName} />
{/if}
<!--ZONE 3.A : TICKET DE CARBURANT-->
{#if shared.waterfall.name === "disponible_to_disponible_apres_taxes_carburant"}
{#each oilSpendings as { depenseTtcVariableName, nombreLitresVariableName, prixTtcLitreVariableName, ticpeVariableName, tvaVariableName }}
<OilSpendingBill
{depenseTtcVariableName}
{nombreLitresVariableName}
{prixTtcLitreVariableName}
on:changeTestCaseToEditIndex
{situation}
{situationIndex}
{ticpeVariableName}
{tvaVariableName}
{valuesByCalculationNameByVariableName}
{year}
/>
{/each}
{:else}
<!--ZONE 3.B : GRAPHIQUE DES CAS TYPES-->
{#if firstPersonActivity !== "inactif"}
<button
class="mt-10 flex w-full items-center gap-2 border-b px-4 py-2 text-start text-neutral-600 transition-all hover:bg-neutral-100 active:bg-neutral-200"
onclick={() => {
if (situation.slider === undefined) {
requestAxesCalculation()
trackTestCaseGraph(firstPersonActivity)
} else {
removeSituationSlider()
}
}}
>
<iconify-icon class="text-lg" icon="ri-line-chart-fill"></iconify-icon>
<span class="flex-1 font-bold">
Voir ce cas type sur un graphique faisant évoluer {#if firstPersonActivity === "actif"}
le salaire
{:else if firstPersonActivity === "retraite"}
la retraite
{:else if firstPersonActivity === "chomeur"}
le chômage
{:else}
le revenu
{/if}
:
</span>
<iconify-icon
class="text-3xl"
icon={situation.slider !== undefined
? "ri-arrow-drop-down-line"
: "ri-arrow-drop-right-line"}
></iconify-icon>
</button>
<TestCaseGraph
{displayMode}
{evaluationByName}
evaluationByNameArray={shared.evaluationByNameArray}
{situation}
{situationIndex}
{useRevaluationInsteadOfLaw}
{valuesByCalculationNameByVariableName}
{variableSummaryByName}
vectorLength={shared.vectorLength}
waterfall={shared.waterfall}
{year}
/>
{/if}
{/if}
{/if}
<style lang="postcss">
.fond {
background-color: #ffffff;
/* Polka dots - Heropatterns.com échelle réduite */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3E%3Cpath fill='%23A0A0A0' fill-opacity='0.4' d='M1 3h1v1H1V3zm2-2h1v1H3V1z'%3E%3C/path%3E%3C/svg%3E");
}
</style>
<script lang="ts">
import { preventDefault } from "svelte/legacy"
import type { VariableByName } from "@openfisca/json-model"
import { goto } from "$app/navigation"
import { page } from "$app/stores"
import Tooltip from "$lib/components/ui_transverse_components/Tooltip.svelte"
import type {
EvaluationByName,
VisibleDecompositionForComparison,
} from "$lib/decompositions"
import { buildVisibleDecompositionsForComparison } from "$lib/decompositions"
import type { DisplayMode } from "$lib/displays"
import { entityByKey } from "$lib/entities"
import { shared } from "$lib/shared.svelte"
import type { Situation } from "$lib/situations"
import { newSimulationUrl } from "$lib/urls"
import { removeNegativeZero } from "$lib/values"
interface Props {
displayMode: DisplayMode
evaluationByNameArray: EvaluationByName[]
situations: Situation[]
situationsToCompareIndex: number[]
showLoader?: boolean
variableSummaryByName: VariableByName
year: number
}
let {
displayMode,
evaluationByNameArray,
situations,
situationsToCompareIndex,
showLoader = true,
variableSummaryByName,
year,
}: Props = $props()
const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
.format
const deltaFormatter = (value: number): string =>
new Intl.NumberFormat("fr-FR", {
currency: "EUR",
maximumFractionDigits: 0,
minimumFractionDigits: 0,
signDisplay: "never",
style: "currency",
}).format(removeNegativeZero(value))
let useRevaluationInsteadOfLaw = $derived(
$page.data.revaluationName !== undefined,
)
let firstCalculationName = $derived(
useRevaluationInsteadOfLaw ? "revaluation" : "law",
)
let runningCalculationNames = $derived(
Object.entries(shared.calculationByName)
.filter(([, calculation]) => calculation.running)
.map(([calculationName]) => calculationName),
)
let modificationsAmendmentCount = $derived(
Object.keys(shared.parametricReform).length,
)
let visibleDecompositions: VisibleDecompositionForComparison[] = $state([])
$effect(() => {
visibleDecompositions = buildVisibleDecompositionsForComparison(
shared.decompositionByName,
entityByKey,
situationsToCompareIndex.map(
(situationIndex) => evaluationByNameArray[situationIndex],
),
situationsToCompareIndex.map(
(situationIndex) => situations[situationIndex],
),
variableSummaryByName,
shared.waterfall,
shared.showNulls,
useRevaluationInsteadOfLaw,
shared.vectorLength,
year,
)
})
function* iterToDepth(depth: number): Generator<number, void, unknown> {
for (let i = 0; i < depth; i++) {
yield i
}
}
function zoomIn(index: number) {
let visibleDecomposition = visibleDecompositions[index]
if (
visibleDecomposition === undefined ||
visibleDecomposition.visibleChildren === undefined
) {
return
}
let decomposition = visibleDecomposition.decomposition
if (!decomposition.open) {
shared.decompositionByName[decomposition.name] = {
...decomposition,
open: true,
}
return
}
}
function zoomOut(index: number) {
let visibleDecomposition = visibleDecompositions[index]
if (
visibleDecomposition === undefined ||
visibleDecomposition.visibleChildren === undefined
) {
return
}
let decomposition = visibleDecomposition.decomposition
if (decomposition.open) {
shared.decompositionByName[decomposition.name] = {
...decomposition,
open: false,
}
return
}
}
</script>
{#if visibleDecompositions.length > 0}
<div>
<div class="h-5 bg-gradient-to-b from-gray-100 to-transparent" />
<!--Montants-nuls-->
<div class="mx-1 mb-3 flex justify-start">
<label class="inline-flex cursor-pointer items-center">
<input
type="checkbox"
value=""
class="peer sr-only"
bind:checked={shared.showNulls}
/>
<div
class="peer relative h-6 w-11 shrink-0 rounded-full bg-gray-400 after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-le-bleu peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-0"
></div>
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300"
>Montrer tous les dispositifs, y compris si leur montant est à 0€.</span
>
</label>
</div>
</div>
<!-- Labels and compared amounts of decompositions -->
<div>
{#each visibleDecompositions as { decomposition, depth, rows, trunk, visibleChildren }, index}
<!-- Decomposition label -->
<div class="flex h-7 items-center whitespace-nowrap">
{#if trunk}
<div
class="ml-2 mt-2 w-full overflow-x-hidden text-ellipsis border-gray-300 text-left text-base text-gray-500 hover:z-20 hover:overflow-x-visible"
class:border-t={index !== 0}
>
{#if displayMode.edit !== undefined}
<!-- Trunk decomposition node, in variable inputs mode => link -->
<a
class="cursor-pointer text-base hover:underline"
href={newSimulationUrl({
...displayMode,
variableName: decomposition.name,
})}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
{:else}
<!-- Trunk decomposition node with parameters, in parameters mode => link -->
<a
class="cursor-pointer text-base hover:underline"
href={newSimulationUrl({
...displayMode,
mobileLaw: true,
parametersVariableName: decomposition.name,
})}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
{/if}
</div>
{:else}
{#each [...iterToDepth(depth)] as _level}
<div class="ml-2 h-full border-l border-le-gris-dispositif">
&nbsp;
</div>
{/each}
{#if visibleChildren === undefined}
<!-- Leaf node (except the first one, that belongs to trunk) -->
<div class="ml-4">
{#if decomposition.obsolete || decomposition.last_value_still_valid_on === undefined || decomposition.last_value_still_valid_on < (new Date().getFullYear() - 2).toString()}
<Tooltip
allowFlip={false}
arrowClass="bg-gray-100"
widthClass="w-80"
initialPlacement="bottom"
>
<iconify-icon
class="mr-1 shadow-none {decomposition.obsolete
? 'text-[#FF4133]'
: 'text-[#FFAC33]'}"
icon="material-symbols:warning-rounded"
width="16"
height="16"
></iconify-icon>
{#snippet tooltip()}
<div
class="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl"
>
<div
class="border-b border-gray-200 bg-gray-100 px-3 py-2"
>
<h3 class="font-semibold text-gray-900">
⚠️ Ce dispositif n'est peut-être pas à jour
</h3>
</div>
<div class="px-3 py-2 text-sm font-light text-gray-500">
Dernière relecture :
{#if decomposition.last_value_still_valid_on === undefined}
date indéterminée
{:else}{dateFormatter(
new Date(decomposition.last_value_still_valid_on),
)}
{/if}
{#if decomposition.obsolete}
; Obsolète !{/if}
</div>
</div>
{/snippet}
</Tooltip>
{/if}
</div>
{#if displayMode.edit !== undefined}
<!-- Leaf decomposition node in variable inputs mode => link -->
<a
class="cursor-pointer overflow-x-hidden text-ellipsis font-serif text-base hover:z-20 hover:overflow-x-visible hover:bg-white hover:text-le-gris-dispositif hover:underline"
href={newSimulationUrl({
...displayMode,
variableName: decomposition.name,
})}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
{:else}
<!-- Leaf decomposition node with parameters in parameters mode => link -->
<a
class="cursor-pointer overflow-x-hidden text-ellipsis font-serif text-base hover:z-20 hover:overflow-x-visible hover:bg-white hover:text-le-gris-dispositif hover:underline"
href={newSimulationUrl({
...displayMode,
mobileLaw: true,
parametersVariableName: decomposition.name,
})}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
{/if}
{:else}
<!-- Non-trunk, non-leaf variablev-->
{#if decomposition.open}
<button class="p-0 text-black" onclick={() => zoomOut(index)}>
<iconify-icon
class="align-[-0.2rem] text-lg"
icon="ri-arrow-up-s-line"
></iconify-icon>
</button>
{:else}
<button class="p-0 text-black" onclick={() => zoomIn(index)}>
<iconify-icon
class="align-[-0.2rem] text-lg"
icon="ri-arrow-right-s-line"
></iconify-icon>
</button>
{/if}
{#if displayMode.edit !== undefined}
<!-- Non-lead decomposition node in variable inputs mode => no-link -->
<button
class="cursor-pointer overflow-x-hidden text-ellipsis font-serif text-base text-black hover:z-20 hover:overflow-x-visible hover:bg-white hover:text-black hover:underline"
onclick={() => {
if (decomposition.open) {
zoomOut(index)
} else {
zoomIn(index)
}
}}
>
{decomposition.short_label ?? decomposition.label}
</button>
{:else}
<!-- Leaf decomposition node with parameters in parameters mode => link -->
<a
class="cursor-pointer overflow-x-hidden text-ellipsis font-serif text-base hover:z-20 hover:overflow-x-visible hover:bg-white hover:text-le-gris-dispositif hover:underline"
href={newSimulationUrl({
...displayMode,
parametersVariableName: decomposition.name,
})}
onclick={preventDefault(() => {
if (decomposition.open) {
zoomOut(index)
} else {
zoomIn(index)
}
goto(
newSimulationUrl({
...displayMode,
parametersVariableName: decomposition.name,
}),
{ noScroll: true },
)
})}
data-sveltekit-noscroll
>{decomposition.short_label ?? decomposition.label}</a
>
{/if}
{/if}
{/if}
</div>
{#each rows as { calculationName, deltaAtVectorIndexArray }}
<!-- Decomposition compared amounts -->
{#if !decomposition.open || trunk || index === 0}
<div class="relative flex items-center whitespace-nowrap">
{#if !decomposition.open && !trunk}
<div class="absolute">
{#each iterToDepth(depth)}
<div class="ml-2 h-full border-l border-le-gris-dispositif">
&nbsp;
</div>
{/each}
</div>
{/if}
<div
class="justify-center {decomposition.open &&
trunk &&
visibleChildren.length > 1 &&
calculationName === firstCalculationName
? ''
: ' border-none'} {calculationName === firstCalculationName
? ''
: '-mt-1 mb-1'} flex w-full text-sm"
>
{#if decomposition.open || index === 0}
<!---Composant loader pour les valeurs intermédiaires-->
{#if showLoader && runningCalculationNames.length > 0}
{#if runningCalculationNames.includes("law") || runningCalculationNames.includes("revaluation")}<span
class="mx-1 animate-pulse-2 bg-gray-500 px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("bill")}
<span
class="mx-1 animate-pulse-2 bg-le-rouge-bill px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("amendment") && modificationsAmendmentCount > 0}
<span
class="mx-1 animate-pulse-2 bg-le-jaune px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
<!--Valeurs du waterfall des montants intermédiaires -->
{:else if trunk || index === 0}
{#if deltaAtVectorIndexArray[0] === deltaAtVectorIndexArray[1]}
{#if decomposition.open && trunk}
<span class="mx-2 text-gray-500">=</span>
{/if}
<span
class="text-sm {calculationName === firstCalculationName
? rows.find((row) => row.calculationName === 'bill') ===
undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-gray-500'
: 'text-gray-500 line-through-amendment'
: 'text-gray-500 line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(deltaAtVectorIndexArray[0] ?? 0)}</span
>
{:else}
<div class="flex w-full justify-center">
<div class="mx-4 w-1/2">
{#if decomposition.open && trunk}
<span class="mx-2 text-gray-500">=</span>
{/if}
<span
class="text-right text-sm {calculationName ===
firstCalculationName
? rows.find(
(row) => row.calculationName === 'bill',
) === undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-gray-500'
: 'text-gray-500 line-through-amendment'
: 'text-gray-500 line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(
deltaAtVectorIndexArray[0] ?? 0,
)}</span
>
</div>
<div class="mx-4 w-1/2">
{#if decomposition.open && trunk}
<span class="mx-2 text-gray-500">=</span>
{/if}
<span
class="text-left text-sm {calculationName ===
firstCalculationName
? rows.find(
(row) => row.calculationName === 'bill',
) === undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-gray-500'
: 'text-gray-500 line-through-amendment'
: 'text-gray-500 line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(
deltaAtVectorIndexArray[1] ?? 0,
)}</span
>
</div>
</div>
{/if}
{/if}
<!--Montant des dispositifs-->
{:else if deltaAtVectorIndexArray[0] === deltaAtVectorIndexArray[1]}
<!---Composant loader pour la valeur suivante-->
{#if showLoader && runningCalculationNames.length > 0}
{#if runningCalculationNames.includes("law") || runningCalculationNames.includes("revaluation")}<span
class="mx-1 animate-pulse-2 bg-gray-500 px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("bill")}
<span
class="mx-1 animate-pulse-2 bg-le-rouge-bill px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("amendment") && modificationsAmendmentCount > 0}
<span
class="mx-1 animate-pulse-2 bg-le-jaune px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
<!--Valeur-->
{:else}
<span
class="text-base font-bold {calculationName ===
firstCalculationName
? rows.find((row) => row.calculationName === 'bill') ===
undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? ''
: 'line-through-amendment'
: 'line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(deltaAtVectorIndexArray[0] ?? 0)}</span
>
{/if}
{:else}
<!---Composant loader pour la valeur suivante-->
{#if showLoader && runningCalculationNames.length > 0}
{#if runningCalculationNames.includes("law") || runningCalculationNames.includes("revaluation")}<span
class="mx-1 animate-pulse-2 bg-gray-500 px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("bill")}
<span
class="mx-1 animate-pulse-2 bg-le-rouge-bill px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
{#if runningCalculationNames.includes("amendment") && modificationsAmendmentCount > 0}
<span
class="mx-1 animate-pulse-2 bg-le-jaune px-1 text-black blur-xs"
>
<span class="text-white blur">value €</span>
</span>
{/if}
<!--Valeur dispositifs-->
{:else}
<div class="flex w-full justify-center">
<div class="mx-4 w-1/2">
<span
class="text-base font-bold {calculationName ===
firstCalculationName
? rows.find(
(row) => row.calculationName === 'bill',
) === undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? ''
: 'line-through-amendment'
: 'line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(deltaAtVectorIndexArray[0] ?? 0)}</span
>
</div>
<div class="mx-4 w-1/2">
<span
class="text-base font-bold {calculationName ===
firstCalculationName
? rows.find(
(row) => row.calculationName === 'bill',
) === undefined
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? ''
: 'line-through-amendment'
: 'line-through-bill'
: calculationName === 'bill'
? rows.find(
(row) => row.calculationName === 'amendment',
) === undefined
? 'text-le-rouge-bill'
: 'text-le-rouge-bill line-through-amendment'
: 'bg-le-jaune'}"
>{deltaFormatter(deltaAtVectorIndexArray[1] ?? 0)}</span
>
</div>
</div>
{/if}
{/if}
</div>
</div>
{/if}
{/each}
{/each}
</div>
{/if}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment