Skip to content

Commit 6387231

Browse files
Changes before error encountered
Co-authored-by: delicatacurtis <[email protected]>
1 parent df238e9 commit 6387231

File tree

5 files changed

+340
-18
lines changed

5 files changed

+340
-18
lines changed

app/Filament/App/Widgets/FamilyTreeOverviewWidget.php

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,43 @@ private function buildMiniTree($person, $maxGenerations, $currentGen = 1): array
6161

6262
private function calculateGenerations(): int
6363
{
64-
// Simple calculation - could be more sophisticated
65-
return Person::selectRaw('MAX(CASE WHEN deathday IS NULL THEN 0 ELSE YEAR(CURDATE()) - YEAR(birthday) END) / 25 as generations')
66-
->value('generations') ?? 1;
64+
// Calculate actual depth by finding the deepest ancestor chain
65+
$maxDepth = 0;
66+
$people = Person::whereNotNull('child_in_family_id')->with('childInFamily')->get();
67+
68+
foreach ($people as $person) {
69+
$depth = $this->calculatePersonDepth($person);
70+
$maxDepth = max($maxDepth, $depth);
71+
}
72+
73+
return max($maxDepth, 1);
74+
}
75+
76+
private function calculatePersonDepth(Person $person, int $currentDepth = 1, array &$visited = []): int
77+
{
78+
// Prevent infinite loops in case of data issues
79+
if (in_array($person->id, $visited)) {
80+
return $currentDepth;
81+
}
82+
83+
$visited[] = $person->id;
84+
85+
if (!$person->childInFamily) {
86+
return $currentDepth;
87+
}
88+
89+
$maxParentDepth = $currentDepth;
90+
91+
if ($person->childInFamily->husband) {
92+
$fatherDepth = $this->calculatePersonDepth($person->childInFamily->husband, $currentDepth + 1, $visited);
93+
$maxParentDepth = max($maxParentDepth, $fatherDepth);
94+
}
95+
96+
if ($person->childInFamily->wife) {
97+
$motherDepth = $this->calculatePersonDepth($person->childInFamily->wife, $currentDepth + 1, $visited);
98+
$maxParentDepth = max($maxParentDepth, $motherDepth);
99+
}
100+
101+
return $maxParentDepth;
67102
}
68103
}

app/Livewire/FamilyTreeBuilder.php

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,42 +42,77 @@ private function loadTreeData(): void
4242
#[On('personMoved')]
4343
public function updatePersonPosition(int $personId, float $x, float $y): void
4444
{
45-
Person::find($personId)?->update([
45+
$person = Person::find($personId);
46+
47+
if (!$person) {
48+
$this->dispatch('error', message: 'Person not found');
49+
return;
50+
}
51+
52+
$person->update([
4653
'tree_position_x' => $x,
4754
'tree_position_y' => $y
4855
]);
4956

50-
$this->emit('positionUpdated', personId: $personId);
57+
$this->dispatch('positionUpdated', personId: $personId);
5158
}
5259

5360
#[On('personAdded')]
5461
public function addPerson(array $data): void
5562
{
56-
$person = Person::create([
57-
'name' => $data['name'],
63+
// Validate required fields
64+
if (empty($data['givn']) && empty($data['surn'])) {
65+
$this->dispatch('error', message: 'Either given name or surname is required');
66+
return;
67+
}
68+
69+
$personData = [
5870
'givn' => $data['givn'] ?? '',
5971
'surn' => $data['surn'] ?? '',
6072
'sex' => $data['sex'] ?? 'U',
61-
'tree_position_x' => $data['position']['x'],
62-
'tree_position_y' => $data['position']['y']
63-
]);
73+
'tree_position_x' => $data['position']['x'] ?? 0,
74+
'tree_position_y' => $data['position']['y'] ?? 0,
75+
];
76+
77+
// Add optional fields if provided
78+
if (isset($data['birthday'])) {
79+
$personData['birthday'] = $data['birthday'];
80+
}
81+
if (isset($data['child_in_family_id'])) {
82+
$personData['child_in_family_id'] = $data['child_in_family_id'];
83+
}
84+
85+
$person = Person::create($personData);
6486

6587
$this->loadTreeData();
66-
$this->emit('personCreated', personId: $person->id);
88+
$this->dispatch('personCreated', personId: $person->id);
6789
}
6890

6991
#[On('personRemoved')]
7092
public function removePerson(int $personId): void
7193
{
72-
Person::find($personId)?->delete();
94+
$person = Person::find($personId);
95+
96+
if (!$person) {
97+
$this->dispatch('error', message: 'Person not found');
98+
return;
99+
}
100+
101+
$person->delete();
73102
$this->loadTreeData();
74-
$this->emit('personDeleted', personId: $personId);
103+
$this->dispatch('personDeleted', personId: $personId);
75104
}
76105

77106
public function selectPerson(int $personId): void
78107
{
79108
$this->selectedPerson = Person::find($personId);
80-
$this->emit('personSelected', personId: $personId);
109+
110+
if (!$this->selectedPerson) {
111+
$this->dispatch('error', message: 'Person not found');
112+
return;
113+
}
114+
115+
$this->dispatch('personSelected', personId: $personId);
81116
}
82117

83118
public function render()

app/Models/Tree.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use Illuminate\Database\Eloquent\Factories\HasFactory;
66
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8+
use Illuminate\Database\Eloquent\Relations\HasMany;
79

810
class Tree extends Model
911
{
@@ -16,5 +18,121 @@ class Tree extends Model
1618
'user_id',
1719
'name',
1820
'description',
21+
'root_person_id',
1922
];
23+
24+
/**
25+
* Get the user that owns the tree.
26+
*/
27+
public function user(): BelongsTo
28+
{
29+
return $this->belongsTo(User::class);
30+
}
31+
32+
/**
33+
* Get the root person of the tree.
34+
*/
35+
public function rootPerson(): BelongsTo
36+
{
37+
return $this->belongsTo(Person::class, 'root_person_id');
38+
}
39+
40+
/**
41+
* Get statistics for this tree.
42+
*/
43+
public function getStats(): array
44+
{
45+
if (!$this->rootPerson) {
46+
return [
47+
'total_people' => 0,
48+
'total_ancestors' => 0,
49+
'total_descendants' => 0,
50+
'total_generations' => 0,
51+
];
52+
}
53+
54+
$treeService = app(\App\Modules\Tree\Services\TreeBuilderService::class);
55+
56+
$ancestors = $treeService->getAllAncestors($this->rootPerson);
57+
$descendants = $treeService->getAllDescendants($this->rootPerson);
58+
59+
// Calculate total unique people
60+
$allPeople = collect([$this->rootPerson])
61+
->merge($ancestors)
62+
->merge($descendants)
63+
->unique('id');
64+
65+
return [
66+
'total_people' => $allPeople->count(),
67+
'total_ancestors' => $ancestors->count(),
68+
'total_descendants' => $descendants->count(),
69+
'total_generations' => $this->calculateTreeDepth(),
70+
];
71+
}
72+
73+
/**
74+
* Calculate the depth of the tree (maximum generations).
75+
*/
76+
private function calculateTreeDepth(): int
77+
{
78+
if (!$this->rootPerson) {
79+
return 0;
80+
}
81+
82+
$treeService = app(\App\Modules\Tree\Services\TreeBuilderService::class);
83+
84+
// Get max ancestor depth
85+
$maxAncestorDepth = $this->getAncestorDepth($this->rootPerson);
86+
87+
// Get max descendant depth
88+
$maxDescendantDepth = $this->getDescendantDepth($this->rootPerson);
89+
90+
return $maxAncestorDepth + $maxDescendantDepth;
91+
}
92+
93+
/**
94+
* Calculate ancestor depth recursively.
95+
*/
96+
private function getAncestorDepth(Person $person, int $depth = 0): int
97+
{
98+
if (!$person->childInFamily) {
99+
return $depth;
100+
}
101+
102+
$maxDepth = $depth;
103+
104+
if ($person->childInFamily->husband) {
105+
$maxDepth = max($maxDepth, $this->getAncestorDepth($person->childInFamily->husband, $depth + 1));
106+
}
107+
108+
if ($person->childInFamily->wife) {
109+
$maxDepth = max($maxDepth, $this->getAncestorDepth($person->childInFamily->wife, $depth + 1));
110+
}
111+
112+
return $maxDepth;
113+
}
114+
115+
/**
116+
* Calculate descendant depth recursively.
117+
*/
118+
private function getDescendantDepth(Person $person, int $depth = 0): int
119+
{
120+
$families = $person->familiesAsHusband->merge($person->familiesAsWife);
121+
122+
if ($families->isEmpty()) {
123+
return $depth;
124+
}
125+
126+
$maxDepth = $depth;
127+
128+
foreach ($families as $family) {
129+
$children = Person::where('child_in_family_id', $family->id)->get();
130+
131+
foreach ($children as $child) {
132+
$maxDepth = max($maxDepth, $this->getDescendantDepth($child, $depth + 1));
133+
}
134+
}
135+
136+
return $maxDepth;
137+
}
20138
}

0 commit comments

Comments
 (0)