Skip to main content

Overview

EpiNeko uses a status system to categorize anime in your library based on your viewing progress and intentions. This helps organize your collection and provides meaningful statistics about your viewing habits.

Watching

Currently watching and actively following

Completed

Finished watching all available episodes

Plan to Watch

Added to library but not started yet

Dropped

Started but decided not to continue

Status Type Definition

The watch status is defined as a TypeScript union type and PostgreSQL enum:
export type LibraryStatus = 'watching' | 'completed' | 'dropped' | 'plan_to_watch';
Database Enum (supabase/migrations/20260218_initial_schema.sql:45):
create type public.library_status as enum (
  'watching', 
  'completed', 
  'dropped', 
  'plan_to_watch'
);
The enum is defined at the database level, ensuring data integrity and preventing invalid status values.

Status Details

Watching (watching)

Indicates you are currently watching this anime and actively following new episodes or continuing through the series.
watching
LibraryStatus
Label: 📺 VIENDOWhen to use:
  • You’re actively watching episodes
  • You’re keeping up with currently airing episodes
  • You plan to watch the next episode soon
Typical behavior:
  • Appears in “Currently Watching” sections
  • Updates episode count as you progress
  • Used for tracking active viewing
Example Usage:
await addToLibrary({
  anime_id_jikan: 52991,
  title: "Sousou no Frieren",
  status: 'watching',
  episodes_watched: 12
});

Completed (completed)

Marks an anime as finished - you’ve watched all available episodes.
completed
LibraryStatus
Label: ✅ COMPLETADOWhen to use:
  • You’ve finished all episodes
  • Series has ended and you’ve seen it all
  • You’ve watched everything currently available for ongoing series
Automatic behavior:
  • Automatically set when episodes_watched equals total episodes
  • Contributes to completion rate statistics
  • Enables scoring/rating
Auto-completion Logic (src/components/anime/EpisodeList.tsx:49-50):
const isCompleted = totalEpisodes ? newCount >= totalEpisodes : false;
const newStatus: LibraryStatus = isCompleted ? 'completed' : 'watching';
Example:
// Manual completion
await updateLibraryItem(52991, { 
  status: 'completed',
  episodes_watched: 28,
  score: 9
});

Plan to Watch (plan_to_watch)

Added to your library but not started watching yet.
plan_to_watch
LibraryStatus
Label: ⏳ PENDIENTEWhen to use:
  • You want to watch it later
  • You’re building a watchlist
  • You’re interested but don’t have time now
Default behavior:
  • Default status when adding from AnimeDetailsModal
  • Often used with episodes_watched: 0
  • Acts as a bookmark or wishlist
Default Status (src/components/anime/AnimeDetailsModal.tsx:54):
const item: LibraryItem = {
  anime_id_jikan: anime.mal_id,
  title: anime.title,
  image_url: anime.image,
  status: 'plan_to_watch',  // Default when adding
};
Example:
// Add to watchlist
await addToLibrary({
  anime_id_jikan: 54595,
  title: "Chainsaw Man",
  status: 'plan_to_watch',
  episodes_watched: 0
});

Dropped (dropped)

You started watching but decided not to continue.
dropped
LibraryStatus
Label: ❌ ABANDONADOWhen to use:
  • You started but lost interest
  • Not enjoying the series
  • Decided it’s not for you
Purpose:
  • Keeps record of what you’ve tried
  • Prevents re-adding by mistake
  • Provides honest viewing statistics
Example:
await updateLibraryItem(12345, { 
  status: 'dropped',
  episodes_watched: 3  // Stopped after episode 3
});

Status Labels

UI-friendly labels with emojis for each status:
const statusLabels: Record<LibraryStatus, string> = {
  watching: '📺 VIENDO',
  completed: '✅ COMPLETADO',
  plan_to_watch: '⏳ PENDIENTE',
  dropped: '❌ ABANDONADO'
};
Implementation (src/components/anime/LibraryButton.tsx:73-78):
  • Used in dropdown menus
  • Displayed on profile statistics
  • Shown in library filters

Changing Status

Via LibraryButton

The LibraryButton component provides a dropdown to change status:
1

Click Main Button

Adds anime to library with default status or removes if already in library
2

Status Dropdown Appears

Only visible when anime is in library
3

Select New Status

Click any status from the dropdown menu
4

Update Applied

Library item is updated with new status
Code Example (src/components/anime/LibraryButton.tsx:96-113):
{isInLibrary && (
  <div className="dropdown">
    <button className="btn">{statusLabels[status]}</button>
    <ul className="dropdown-content menu">
      {(Object.keys(statusLabels) as LibraryStatus[]).map((s) => (
        <li key={s}>
          <button 
            onClick={() => handleLibraryAction(s)}
            className={status === s ? 'text-primary' : 'text-zinc-400'}
          >
            {statusLabels[s]}
          </button>
        </li>
      ))}
    </ul>
  </div>
)}

Programmatic Updates

Update status directly via API:
import { updateLibraryItem } from '@/services/library';

// Change to watching
await updateLibraryItem(animeId, { status: 'watching' });

// Mark as completed with score
await updateLibraryItem(animeId, { 
  status: 'completed',
  score: 8
});

// Mark as dropped
await updateLibraryItem(animeId, { status: 'dropped' });

Status-Based Filtering

Filter library by status for organization:
import { getLibrary } from '@/services/library';

const library = await getLibrary();

// Get all watching anime
const watching = library.filter(item => item.status === 'watching');

// Get completed anime
const completed = library.filter(item => item.status === 'completed');

// Get plan to watch
const planToWatch = library.filter(item => item.status === 'plan_to_watch');

// Get dropped
const dropped = library.filter(item => item.status === 'dropped');
Profile Statistics (src/app/profile/page.tsx:49-55):
const stats = {
  total: library.length,
  watching: library.filter(i => i.status === 'watching').length,
  completed: library.filter(i => i.status === 'completed').length,
  planToWatch: library.filter(i => i.status === 'plan_to_watch').length,
  dropped: library.filter(i => i.status === 'dropped').length,
};

Automatic Status Changes

Some status changes happen automatically based on user actions:
When marking episodes as watched:
// If all episodes watched
if (newCount >= totalEpisodes) {
  status = 'completed';
} 
// If some episodes watched
else if (newCount > 0) {
  status = 'watching';
}
// If no episodes watched
else {
  status = 'plan_to_watch';
}
Implementation: src/components/anime/EpisodeList.tsx:44-70

Status Colors

Visual color coding for each status:
.status-watching {
  color: #ff00a8;        /* Primary pink */
  background: #ff00a8/10;
  border: #ff00a8/30;
}
Progress Bar Colors (src/app/profile/page.tsx:151-154):
  • Watching: bg-primary (pink)
  • Completed: bg-green-500
  • Plan to Watch: bg-yellow-500
  • Dropped: bg-red-500

Status Best Practices

Be Honest

Use “dropped” instead of keeping unwatched anime as “watching”Provides accurate viewing statistics

Update Regularly

Change status as your viewing situation changesKeeps library organized and current

Use Plan to Watch

Add interesting anime to “plan to watch” as bookmarksBuild your watchlist for later

Complete Properly

Mark as completed only when fully finishedMakes completion statistics meaningful

Database Constraints

The status field has constraints at the database level:
create table public.user_library (
  -- ...
  status public.library_status default 'watching' not null,
  -- ...
);
Key Points:
  • Status is required (NOT NULL)
  • Must be one of the four enum values
  • Defaults to ‘watching’ if not specified
  • Database rejects invalid values
Attempting to set an invalid status will result in a database error. Always use the predefined LibraryStatus type values.

Status Statistics

View your status distribution on the profile page:
// Calculate percentages
const watchingPercent = (stats.watching / stats.total) * 100;
const completedPercent = (stats.completed / stats.total) * 100;
const planPercent = (stats.planToWatch / stats.total) * 100;
const droppedPercent = (stats.dropped / stats.total) * 100;

// Completion rate
const completionRate = (stats.completed / stats.total) * 100;
Visualization:
  • Progress bars showing distribution
  • Numeric counts for each status
  • Completion percentage calculation
  • Visual color coding