NolanN
NolanN
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
No worries. Praying for a speedy recovery!
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
The countdown-column.blade.php that I just uploaded is stripped down from what it need to be in its final state. It should ultimately be using the countdown store to trigger an update of the countdown every second but I pulled some of that out to try to figure out what is going on
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
No, sorry. It is a private repo. I could upload the view I'm using for the column and the custom page. Would that work for you?
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Is $getStatePath() available on a ViewColumn ?
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
No description
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
I get an undefined variable error
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Ok, let me try that
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
I know that I can use $getRecord()->true_ends_at or $getState() but I need to entangle the property name
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
endTime: $wire.$entangle('{{ $getState() }}') throws errors because it isn't found on the component. How would I specify a field from the record that is associated with that table row?
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
How exactly would I do that?
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Trying to simplify this to narrow down the issue... After changing to the following code, I see that init() is still running when the table polls and finds new data for the true_ends_at column. I can also verify that remaining is changing but the display does not update until the following poll before it updates. So at the moment the sequence is like this: - true_ends_at changes - table polls and new data is printed to console but display does not update - table polls again and there is NOT new data but the display updates with the new data from the previous poll
<div class="grid gap-y-1 px-3 py-4 w-full">
<div x-data="{
remaining: 0,
endTime: new Date('{{ $getState()->toISOString() }}').getTime(),
formatTime(time) {
const days = Math.floor(time / (1000 * 60 * 60 * 24));
const hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((time % (1000 * 60)) / 1000);
return { days, hours, minutes, seconds };
},
updateValues() {
const now = new Date().getTime();
const remaining = this.endTime - now;
this.remaining = remaining > 0 ? remaining : 0;
},
init() {
this.updateValues();
console.log('init: ' + this.remaining + ' ' + this.formatTime(this.remaining).seconds);
},
}">
<div class="font-semibold"
:class="{
'text-red-600 dark:text-red-500': formatTime(remaining).hours <= 0 && formatTime(remaining)
.minutes <=
14
}">
<span x-text="formatTime(remaining).minutes"></span>m
<span x-text="formatTime(remaining).seconds"></span>s
</div>
</div>
</div>
<div class="grid gap-y-1 px-3 py-4 w-full">
<div x-data="{
remaining: 0,
endTime: new Date('{{ $getState()->toISOString() }}').getTime(),
formatTime(time) {
const days = Math.floor(time / (1000 * 60 * 60 * 24));
const hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((time % (1000 * 60)) / 1000);
return { days, hours, minutes, seconds };
},
updateValues() {
const now = new Date().getTime();
const remaining = this.endTime - now;
this.remaining = remaining > 0 ? remaining : 0;
},
init() {
this.updateValues();
console.log('init: ' + this.remaining + ' ' + this.formatTime(this.remaining).seconds);
},
}">
<div class="font-semibold"
:class="{
'text-red-600 dark:text-red-500': formatTime(remaining).hours <= 0 && formatTime(remaining)
.minutes <=
14
}">
<span x-text="formatTime(remaining).minutes"></span>m
<span x-text="formatTime(remaining).seconds"></span>s
</div>
</div>
</div>
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Yeah, it seems that the key would have to match a property in x-data. This watch is not being triggered however, even though the state is changing. I think this is because when the table polls, Alpine is reinitialized. If I add console.log('init') to the beginning of the method, I do see that when the table polls and finds new data
init() {
console.log('init');
$watch('endTime', value => console.log('endTime changed', value))

this.updateValues();
const boundUpdate = this.updateValues.bind(this);
$store.countdown.subscribe($el, boundUpdate);
},
init() {
console.log('init');
$watch('endTime', value => console.log('endTime changed', value))

this.updateValues();
const boundUpdate = this.updateValues.bind(this);
$store.countdown.subscribe($el, boundUpdate);
},
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Ok, I think I see where you are going but I want to clarify a few things. I'm not using x-init so I'll put it in init() instead. Shouldn't this be $watch('endTime', value => ....) instead of $watch('{{ $getState()->toISOString() }}', value => ....)?
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
And the store that is defined on the page:
<x-filament-panels::page>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('countdown', {
subscribers: new Set(),

subscribe(el, callback) {
this.subscribers.add({
el,
callback
});
},

tick() {
this.subscribers.forEach(({
el,
callback
}) => {
if (document.body.contains(el)) {
callback();
} else {
this.subscribers.delete({
el,
callback
});
}
});
}
})
})

if (!window.sharedInterval) {
window.sharedInterval = setInterval(() => {
Alpine.store('countdown').tick();
}, 1000);
}
</script>
<div>
{{ $this->table }}
</div>
</x-filament-panels::page>
<x-filament-panels::page>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('countdown', {
subscribers: new Set(),

subscribe(el, callback) {
this.subscribers.add({
el,
callback
});
},

tick() {
this.subscribers.forEach(({
el,
callback
}) => {
if (document.body.contains(el)) {
callback();
} else {
this.subscribers.delete({
el,
callback
});
}
});
}
})
})

if (!window.sharedInterval) {
window.sharedInterval = setInterval(() => {
Alpine.store('countdown').tick();
}, 1000);
}
</script>
<div>
{{ $this->table }}
</div>
</x-filament-panels::page>
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
The view file that is being passed in:
<div class="grid gap-y-1 px-3 py-4 w-full">
<div x-data="{
past: false,
remaining: 0,
showCountdown: false,
endTime: new Date('{{ $getState()->toISOString() }}').getTime(),
formatTime(time) {
const days = Math.floor(time / (1000 * 60 * 60 * 24));
const hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((time % (1000 * 60)) / 1000);
return { days, hours, minutes, seconds };
},
updateValues() {
const now = new Date().getTime();
const remaining = this.endTime - now;
this.remaining = remaining > 0 ? remaining : 0;
this.past = remaining <= 0;
this.showCountdown = this.formatTime(remaining).hours <= 0 && !this.past;
},
init() {
const boundUpdate = this.updateValues.bind(this);
$store.countdown.subscribe($el, boundUpdate);
},
}">
<template x-if="!showCountdown && !past">
<div class="text-sm font-medium">{{ $getState()->shortAbsoluteDiffForHumans(parts: 2) }}</div>
</template>
<template x-if="showCountdown">
<div class="font-semibold"
:class="{
'text-red-600 dark:text-red-500': formatTime(remaining).hours <= 0 && formatTime(remaining)
.minutes <=
14
}">
<span x-text="formatTime(remaining).minutes"></span>m
<span x-text="formatTime(remaining).seconds"></span>s
</div>
</template>
<template x-if="past">
<div class="text-sm font-medium">Just ended</div>
</template>
</div>
</div>
<div class="grid gap-y-1 px-3 py-4 w-full">
<div x-data="{
past: false,
remaining: 0,
showCountdown: false,
endTime: new Date('{{ $getState()->toISOString() }}').getTime(),
formatTime(time) {
const days = Math.floor(time / (1000 * 60 * 60 * 24));
const hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((time % (1000 * 60)) / 1000);
return { days, hours, minutes, seconds };
},
updateValues() {
const now = new Date().getTime();
const remaining = this.endTime - now;
this.remaining = remaining > 0 ? remaining : 0;
this.past = remaining <= 0;
this.showCountdown = this.formatTime(remaining).hours <= 0 && !this.past;
},
init() {
const boundUpdate = this.updateValues.bind(this);
$store.countdown.subscribe($el, boundUpdate);
},
}">
<template x-if="!showCountdown && !past">
<div class="text-sm font-medium">{{ $getState()->shortAbsoluteDiffForHumans(parts: 2) }}</div>
</template>
<template x-if="showCountdown">
<div class="font-semibold"
:class="{
'text-red-600 dark:text-red-500': formatTime(remaining).hours <= 0 && formatTime(remaining)
.minutes <=
14
}">
<span x-text="formatTime(remaining).minutes"></span>m
<span x-text="formatTime(remaining).seconds"></span>s
</div>
</template>
<template x-if="past">
<div class="text-sm font-medium">Just ended</div>
</template>
</div>
</div>
29 replies
FFilament
Created by NolanN on 1/14/2025 in #❓┊help
Building a complex countdown table column
Here is the column in the table:
Tables\Columns\ViewColumn::make('true_ends_at')
->label('Ends in')
->sortable()
->view('filament.tables.countdown-column')
->tooltip(fn (ReverseAuction $record) => $record->true_ends_at->format(Table::$defaultDateTimeDisplayFormat)),
Tables\Columns\ViewColumn::make('true_ends_at')
->label('Ends in')
->sortable()
->view('filament.tables.countdown-column')
->tooltip(fn (ReverseAuction $record) => $record->true_ends_at->format(Table::$defaultDateTimeDisplayFormat)),
29 replies
FFilament
Created by NolanN on 1/10/2025 in #❓┊help
Show alternate logo when sidebar is collapsed
Gotcha. Maybe I could find a way to release something as a plugin in the meantime
12 replies
FFilament
Created by NolanN on 1/10/2025 in #❓┊help
Show alternate logo when sidebar is collapsed
Ok, I'll see what I can find. Is it best to start a discussion in the ideas category for this?
12 replies
FFilament
Created by NolanN on 1/10/2025 in #❓┊help
Show alternate logo when sidebar is collapsed
No description
12 replies