fix: centralize watchlist dropdown js and fix page load timing
This commit is contained in:
@@ -188,6 +188,7 @@ func (s *playbackService) BuildWatchData(ctx context.Context, animeID int, title
|
|||||||
// 3. Get start time from progress
|
// 3. Get start time from progress
|
||||||
startTime := 0.0
|
startTime := 0.0
|
||||||
var watchlistStatus string
|
var watchlistStatus string
|
||||||
|
var watchlistIDs []int64
|
||||||
if userID != "" {
|
if userID != "" {
|
||||||
entry, err := s.repo.GetWatchListEntry(ctx, db.GetWatchListEntryParams{
|
entry, err := s.repo.GetWatchListEntry(ctx, db.GetWatchListEntryParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
@@ -195,6 +196,7 @@ func (s *playbackService) BuildWatchData(ctx context.Context, animeID int, title
|
|||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
watchlistStatus = entry.Status
|
watchlistStatus = entry.Status
|
||||||
|
watchlistIDs = []int64{entry.AnimeID}
|
||||||
if entry.CurrentEpisode.Valid && strconv.FormatInt(entry.CurrentEpisode.Int64, 10) == episode {
|
if entry.CurrentEpisode.Valid && strconv.FormatInt(entry.CurrentEpisode.Int64, 10) == episode {
|
||||||
startTime = entry.CurrentTimeSeconds
|
startTime = entry.CurrentTimeSeconds
|
||||||
}
|
}
|
||||||
@@ -318,6 +320,7 @@ func (s *playbackService) BuildWatchData(ctx context.Context, animeID int, title
|
|||||||
"Episodes": domainEpisodes,
|
"Episodes": domainEpisodes,
|
||||||
"CurrentEpID": episode,
|
"CurrentEpID": episode,
|
||||||
"WatchlistStatus": watchlistStatus,
|
"WatchlistStatus": watchlistStatus,
|
||||||
|
"WatchlistIDs": watchlistIDs,
|
||||||
"Seasons": seasons,
|
"Seasons": seasons,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,20 @@
|
|||||||
const watchlistIds = new Set()
|
const watchlistIds = new Set()
|
||||||
|
|
||||||
function initWatchlist(ids) {
|
function initWatchlist(ids) {
|
||||||
ids.forEach(id => watchlistIds.add(id))
|
ids.forEach(id => watchlistIds.add(id));
|
||||||
|
const sync = () => ids.forEach(id => syncRemoveButtonVisibility(id));
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', sync);
|
||||||
|
} else {
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncRemoveButtonVisibility(id) {
|
||||||
|
const container = document.getElementById('remove-watchlist-container-' + id);
|
||||||
|
if (container) {
|
||||||
|
container.classList.toggle('hidden', !watchlistIds.has(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleWatchlist(id, btn) {
|
function toggleWatchlist(id, btn) {
|
||||||
@@ -169,10 +182,7 @@ if (window.showToast) showToast({ message: 'Something went wrong' })
|
|||||||
const statusDisplay = document.getElementById('watchlist-status-display-' + id)
|
const statusDisplay = document.getElementById('watchlist-status-display-' + id)
|
||||||
if (statusDisplay) {
|
if (statusDisplay) {
|
||||||
statusDisplay.textContent = inWatchlist ? 'Plan to Watch' : 'Add to Watchlist'
|
statusDisplay.textContent = inWatchlist ? 'Plan to Watch' : 'Add to Watchlist'
|
||||||
const removeContainer = document.getElementById('remove-watchlist-container-' + id)
|
syncRemoveButtonVisibility(id)
|
||||||
if (removeContainer) {
|
|
||||||
removeContainer.classList.toggle('hidden', !inWatchlist)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +196,57 @@ if (window.showToast) showToast({ message: 'Something went wrong' })
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateWatchlist(id, status, display, btn) {
|
||||||
|
fetch('/api/watchlist', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ animeId: id, status: status })
|
||||||
|
}).then(res => {
|
||||||
|
if (res.ok) {
|
||||||
|
watchlistIds.add(id);
|
||||||
|
document.getElementById('watchlist-status-display-' + id).textContent = display;
|
||||||
|
syncRemoveButtonVisibility(id);
|
||||||
|
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
||||||
|
const button = icon.closest('button');
|
||||||
|
if (button) {
|
||||||
|
const malId = button.dataset.malId;
|
||||||
|
if (malId && parseInt(malId) === id) {
|
||||||
|
button.classList.add('in-watchlist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const dropdown = btn.closest('ui-dropdown');
|
||||||
|
if (dropdown) dropdown.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeWatchlist(id, btn) {
|
||||||
|
fetch('/api/watchlist/' + id, { method: 'DELETE' }).then(res => {
|
||||||
|
if (res.ok) {
|
||||||
|
watchlistIds.delete(id);
|
||||||
|
document.getElementById('watchlist-status-display-' + id).textContent = 'Add to Watchlist';
|
||||||
|
syncRemoveButtonVisibility(id);
|
||||||
|
if (window.showToast) showToast({ message: 'Removed from watchlist' });
|
||||||
|
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
||||||
|
const button = icon.closest('button');
|
||||||
|
if (button) {
|
||||||
|
const malId = button.dataset.malId;
|
||||||
|
if (malId && parseInt(malId) === id) {
|
||||||
|
button.classList.remove('in-watchlist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (btn) {
|
||||||
|
const dropdown = btn.closest('ui-dropdown');
|
||||||
|
if (dropdown) dropdown.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-background text-foreground">
|
<body class="bg-background text-foreground">
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
<div id="remove-watchlist-container-{{$anime.MalID}}" class="{{if not $status}}hidden{{end}}">
|
<div id="remove-watchlist-container-{{$anime.MalID}}" class="{{if not $status}}hidden{{end}}">
|
||||||
<div class="my-1 h-px bg-border"></div>
|
<div class="my-1 h-px bg-border"></div>
|
||||||
<button class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-red-500/10 focus:bg-red-500/10" onclick="removeWatchlist({{$anime.MalID}})">
|
<button class="flex w-full items-center px-5 py-2.5 transition-colors focus:outline-none hover:bg-red-500/10 focus:bg-red-500/10" onclick="removeWatchlist({{$anime.MalID}}, this)">
|
||||||
<span class="font-medium text-sm text-red-500 text-left whitespace-nowrap">Remove from Watchlist</span>
|
<span class="font-medium text-sm text-red-500 text-left whitespace-nowrap">Remove from Watchlist</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,65 +50,4 @@
|
|||||||
{{if and .ContinueWatchingEp (ne .ContinueWatchingEp 1)}}Continue Episode {{.ContinueWatchingEp}}{{else}}Watch Now{{end}}
|
{{if and .ContinueWatchingEp (ne .ContinueWatchingEp 1)}}Continue Episode {{.ContinueWatchingEp}}{{else}}Watch Now{{end}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
function updateWatchlist(id, status, display, btn) {
|
|
||||||
fetch('/api/watchlist', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ animeId: id, status: status })
|
|
||||||
}).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
watchlistIds.add(id);
|
|
||||||
document.getElementById('watchlist-status-display-' + id).textContent = display;
|
|
||||||
document.getElementById('remove-watchlist-container-' + id).classList.remove('hidden');
|
|
||||||
|
|
||||||
// Update all watchlist icons on the page
|
|
||||||
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
|
||||||
const button = icon.closest('button')
|
|
||||||
if (button) {
|
|
||||||
const malId = button.dataset.malId
|
|
||||||
if (malId && parseInt(malId) === id) {
|
|
||||||
button.classList.add('in-watchlist')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close dropdown after a small delay to let click event finish
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
const dropdown = btn.closest('ui-dropdown');
|
|
||||||
if (dropdown) dropdown.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeWatchlist(id) {
|
|
||||||
fetch('/api/watchlist/' + id, { method: 'DELETE' }).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
watchlistIds.delete(id);
|
|
||||||
document.getElementById('watchlist-status-display-' + id).textContent = 'Add to Watchlist';
|
|
||||||
document.getElementById('remove-watchlist-container-' + id).classList.add('hidden');
|
|
||||||
|
|
||||||
// Update all watchlist icons on the page
|
|
||||||
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
|
||||||
const button = icon.closest('button')
|
|
||||||
if (button) {
|
|
||||||
const malId = button.dataset.malId
|
|
||||||
if (malId && parseInt(malId) === id) {
|
|
||||||
button.classList.remove('in-watchlist')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close dropdown
|
|
||||||
const btn = document.getElementById('watchlist-status-display-' + id);
|
|
||||||
if (btn) {
|
|
||||||
const dropdown = btn.closest('ui-dropdown');
|
|
||||||
if (dropdown) dropdown.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -164,72 +164,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
if (watchlistIds.has({{$anime.MalID}})) {
|
|
||||||
document.getElementById('remove-watchlist-container-{{$anime.MalID}}').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateWatchlist(id, status, display, btn) {
|
|
||||||
fetch('/api/watchlist', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ animeId: id, status: status })
|
|
||||||
}).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
watchlistIds.add(id);
|
|
||||||
document.getElementById('watchlist-status-display-' + id).textContent = display;
|
|
||||||
document.getElementById('remove-watchlist-container-' + id).classList.remove('hidden');
|
|
||||||
|
|
||||||
// Update all watchlist icons on the page
|
|
||||||
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
|
||||||
const button = icon.closest('button')
|
|
||||||
if (button) {
|
|
||||||
const malId = button.dataset.malId
|
|
||||||
if (malId && parseInt(malId) === id) {
|
|
||||||
button.classList.add('in-watchlist')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close dropdown after a small delay to let click event finish
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
const dropdown = btn.closest('ui-dropdown');
|
|
||||||
if (dropdown) dropdown.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeWatchlist(id, btn) {
|
|
||||||
fetch('/api/watchlist/' + id, { method: 'DELETE' }).then(res => {
|
|
||||||
if (res.ok) {
|
|
||||||
watchlistIds.delete(id);
|
|
||||||
document.getElementById('watchlist-status-display-' + id).textContent = 'Add to Watchlist';
|
|
||||||
document.getElementById('remove-watchlist-container-' + id).classList.add('hidden');
|
|
||||||
if (window.showToast) showToast({ message: 'Removed from watchlist' });
|
|
||||||
|
|
||||||
// Update all watchlist icons on the page
|
|
||||||
document.querySelectorAll('.watchlist-icon').forEach(function(icon) {
|
|
||||||
const button = icon.closest('button')
|
|
||||||
if (button) {
|
|
||||||
const malId = button.dataset.malId
|
|
||||||
if (malId && parseInt(malId) === id) {
|
|
||||||
button.classList.remove('in-watchlist')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close dropdown
|
|
||||||
if (btn) {
|
|
||||||
const dropdown = btn.closest('ui-dropdown');
|
|
||||||
if (dropdown) dropdown.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user