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

Add root as a possible category #96

Merged
merged 7 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 27 additions & 34 deletions components/Categories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { useMe } from '../hooks/useMe'

import RelativeCardList from './RelativeCardList'

type CategoryChecklist = { [key in CategoryName]: boolean }

export default function Categories() {
const mode = useModeContext()

Expand Down Expand Up @@ -51,7 +49,7 @@ export default function Categories() {
<input
className="disabled:cursor-not-allowed"
type="checkbox"
checked={checked[c]}
checked={checked.has(c)}
disabled={isDisabled}
onChange={(e) => onCheckChange(e, c)}
/>
Expand Down Expand Up @@ -80,63 +78,53 @@ export default function Categories() {

function allowedCategories(category: CategoryName, degree: number, mode: Mode): CategoryName[] {
if (mode === 'patrimony') {
if (degree === 0) {
return ['children', 'spouse', 'ascendants']
}
if (category === 'children') {
return ['children']
}
if (category === 'ascendants') {
return ['ascendants']
switch (category) {
case 'root':
return ['children', 'spouse', 'ascendants']
case 'children':
return ['children']
case 'ascendants':
return ['ascendants']
default:
return []
}
return []
}

if (degree === 0) {
return ['children', 'spouse', 'ascendants', 'bilateral', 'unilateral', 'others']
}
switch (category) {
case 'root':
return ['children', 'spouse', 'ascendants', 'bilateral', 'unilateral', 'others']
case 'children':
case 'bilateral': {
case 'bilateral':
return ['children']
}
case 'ascendants': {
case 'ascendants':
if (degree === 1) {
return ['ascendants']
}
return ['children', 'ascendants']
}
default: {
default:
return []
}
}
}

function checkedCategories(list: PersonList, relativeIDs: string[]): CategoryChecklist {
const categories: CategoryChecklist = {
children: false,
spouse: false,
ascendants: false,
bilateral: false,
unilateral: false,
others: false,
}
function checkedCategories(list: PersonList, relativeIDs: string[]): Set<CategoryName> {
const categories: Set<CategoryName> = new Set()

// When a category is checked it auto adds one person to the relatives
// so if there is a person with that category it must be on
for (const relativeID of relativeIDs) {
const relative = list[relativeID]
categories[relative.category] = true
categories.add(relative.category)
}

return categories
}

function disabledCategories(checkedCategories: CategoryChecklist): CategoryName[] {
if (checkedCategories['children']) {
function disabledCategories(checkedCategories: Set<CategoryName>): CategoryName[] {
if (checkedCategories.has('children')) {
return ['ascendants', 'bilateral', 'unilateral', 'others']
}

if (['spouse', 'ascendants', 'bilateral', 'unilateral'].some((c) => checkedCategories[c as CategoryName])) {
if ((['spouse', 'ascendants', 'bilateral', 'unilateral'] as const).some((c) => checkedCategories.has(c))) {
return ['others']
}

Expand All @@ -150,6 +138,11 @@ interface DictionaryEntry {
}

const dictionary: Record<CategoryName, DictionaryEntry> = {
root: {
label: '',
name: '',
description: '',
},
children: {
label: 'Discendenti',
name: 'Discendente',
Expand Down
2 changes: 2 additions & 0 deletions components/RelativeCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,6 @@ function maxHeirs(category: CategoryName): number {
return 2
}
}

return 0
}
6 changes: 3 additions & 3 deletions components/RelativesForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default function RelativesForm({ isLoading, onSubmit }: RelativesFormProp

<div className="flex flex-col gap-2 rounded-md bg-gray-50 px-4 pt-5 pb-6 md:flex-row md:justify-between">
{!isRoot && (
<Link href={`?id=${me.root ?? '0'}`}>
<Link href={`?id=${me.previous ?? '0'}`}>
<a className="btn btn-inverted px-8">Indietro</a>
</Link>
)}
Expand All @@ -68,11 +68,11 @@ export function toNonEmptyName(name: string): string {

function getPagination(list: PersonList, me: Person): { id: string; name: string }[] {
const pagination = [{ id: me.id, name: toNonEmptyName(me.name) }]
let root = me.root
let root = me.previous
while (root !== null) {
const parent = list[root]
pagination.push({ id: parent.id, name: toNonEmptyName(parent.name) })
root = parent.root
root = parent.previous
}

return pagination
Expand Down
9 changes: 5 additions & 4 deletions components/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function relativesSort(a: Person, b: Person): number {
}

const categoryRelation: Record<CategoryName, string> = {
root: '',
children: 'Figlio/a di',
spouse: 'Coniuge di',
ascendants: 'Genitore di',
Expand Down Expand Up @@ -104,7 +105,7 @@ function Results({ inheritance, setEditing }: ResultsProps) {
<tbody>
{allRelatives.map((relativeId) => {
const relative = list[relativeId]
if (relative.root === null) return
if (relative.previous === null) return

const relativeInheritance = inheritance[relativeId]
const inheritanceValue = new Fraction(relativeInheritance).valueOf()
Expand All @@ -120,7 +121,7 @@ function Results({ inheritance, setEditing }: ResultsProps) {
<div className="py-2 px-4">
<p className="font-medium text-gray-800">{relative.name}</p>
<p className="text-sm text-gray-600 md:text-base">
{relation} {list[relative.root].name}
{relation} {list[relative.previous].name}
</p>
</div>
</td>
Expand Down Expand Up @@ -159,8 +160,8 @@ export default Results
function countDepth(list: PersonList, id: string): number {
let depth = -1
let currentRelative = list[id]
while (currentRelative.root) {
currentRelative = list[currentRelative.root]
while (currentRelative.previous) {
currentRelative = list[currentRelative.previous]
depth += 1
}
return depth
Expand Down
10 changes: 5 additions & 5 deletions context/PeopleContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ export function peopleReducer(state: PersonList, action: PeopleAction): PersonLi

case 'REMOVE_RELATIVE': {
const relative = { ...state[payload.id] }
if (!relative.root) return state
if (!relative.previous) return state
// remove self from parent relative
const parent = { ...state[relative.root] }
const parent = { ...state[relative.previous] }
const nextParent = { ...parent, relatives: parent.relatives.filter((id) => id !== relative.id) }

// remove every own relative
Expand Down Expand Up @@ -161,7 +161,7 @@ function createPerson(category: CategoryName, parent: Person): Person {
name: '',
available: true,
degree,
root: parent.id,
previous: parent.id,
category,
relatives: [] as string[],
}
Expand All @@ -188,8 +188,8 @@ const initialPeople: PersonList = {
name: 'Defunto',
available: false,
degree: 0,
root: null,
category: 'children',
previous: null,
category: 'root',
relatives: [],
},
}
54 changes: 26 additions & 28 deletions core/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ function isPersonEligible(
function addEligibleRelativeToRoot(list: PersonList, relative: Person) {
// Recursively append relative to its root
let current = relative
while (current.root !== null) {
if (!list[current.root]) {
throw new Error(`Could not find person corresponding to id: ${current.root}`)
while (current.previous !== null) {
if (!list[current.previous]) {
throw new Error(`Could not find person corresponding to id: ${current.previous}`)
}
// current element is already in the root, we're finished here
if (list[current.root].relatives.find((id) => id === current.id) !== undefined) {
if (list[current.previous].relatives.find((id) => id === current.id) !== undefined) {
break
}

list[current.root].relatives.push(current.id)
current = list[current.root]
list[current.previous].relatives.push(current.id)
current = list[current.previous]
}
}

Expand All @@ -67,19 +67,22 @@ function hasRepresentationRight(list: PersonList, current: Person, rootId: strin
}

// Current person is a direct child or bilateral sibling of the root
if (current.root === rootId && (current.category === 'children' || current.category === 'bilateral')) {
if (
current.previous === rootId &&
(current.category === 'root' || current.category === 'children' || current.category === 'bilateral')
) {
return true
}

// If everyone in their family line had the right they have it as well
let parentHadRepresentationRight = true
while (current.root !== null && parentHadRepresentationRight) {
const parent = list[current.root]
while (current.previous !== null && parentHadRepresentationRight) {
const parent = list[current.previous]
if (!parent) {
throw new Error(`Could not find parent with id: ${current.root}`)
throw new Error(`Could not find parent with id: ${current.previous}`)
}

if (!(parent.category === 'children' || parent.category === 'bilateral')) {
if (!(parent.category === 'root' || parent.category === 'children' || parent.category === 'bilateral')) {
parentHadRepresentationRight = false
}
current = parent
Expand All @@ -92,11 +95,11 @@ function hasRepresentationRight(list: PersonList, current: Person, rootId: strin
export function stripGraph(
list: PersonList,
root: Person,
getRelevantCategories: (isRoot: boolean, person: Person) => string[]
getRelevantCategories: (person: Person) => string[]
): PersonList {
const visited: Record<string, boolean> = { [root.id]: true }

const visited: Set<string> = new Set(root.id)
const queue: string[] = [root.id]

let maxDegree = Infinity
let maxAscendantDegree = Infinity

Expand Down Expand Up @@ -128,30 +131,25 @@ export function stripGraph(
}

// Could also try checking if root is null but I want to get object validation going first
const isRoot = person.id === root.id
const categories = getRelevantCategories(isRoot, person)
const categories = getRelevantCategories(person)
if (categories.length === 0) {
continue
}

const relatives = person.relatives.filter((id) => {
const relative = list[id]
if (!relative) {
throw new Error(`Could not find relative with id: ${id}`)
for (const relativeId of person.relatives) {
if (visited.has(relativeId)) {
continue
}
return categories.includes(list[id].category)
})

for (const relativeId of relatives) {
if (visited[relativeId]) {
const relative = list[relativeId]
if (!categories.includes(relative.category)) {
continue
}

const relative = list[relativeId]
relative.root = person.id
relative.previous = person.id
relative.degree = getDegree(relative, person)

visited[relative.id] = true
visited.add(relative.id)
queue.push(relative.id)
}

Expand Down Expand Up @@ -188,7 +186,7 @@ export function stripGraph(
if (!person) {
throw new Error(`Could not find other relative with id: ${otherId}`)
}
person.root = root.id
person.previous = root.id

if (person.available && person.degree <= DEGREE_CUTOFF && !isDegreeTooHigh(person, maxDegree, Infinity)) {
maxDegree = person.degree
Expand Down
Loading
Loading