- Rewrote frontend from JSX to TypeScript (TSX) - AppLayout with MUI AppBar, ThemeProvider, CssBaseline - HomePage at / with dashboard metrics and recent updates - MetricsPanel with 4 metric cards (total, interviews, offers, rejection rate) - UpdateCard for each job update with status chip - LoadingSkeleton during data fetch - Error Alert on API failure - Create New Job Application button navigating to /applications/new - Vite proxy for /api → backend on :8000 - useDashboardData custom hook with concurrent fetch Closes #2
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
from django.db import models
|
|
|
|
|
|
class StatusChoices(models.TextChoices):
|
|
APPLIED = "APPLIED", "Applied"
|
|
SCREENING = "SCREENING", "Screening"
|
|
INTERVIEW = "INTERVIEW", "Interview"
|
|
OFFER = "OFFER", "Offer"
|
|
REJECTED = "REJECTED", "Rejected"
|
|
WITHDRAWN = "WITHDRAWN", "Withdrawn"
|
|
|
|
|
|
class JobApplication(models.Model):
|
|
company_name = models.CharField(max_length=255)
|
|
position_title = models.CharField(max_length=255)
|
|
status = models.CharField(
|
|
max_length=20,
|
|
choices=StatusChoices.choices,
|
|
default=StatusChoices.APPLIED,
|
|
)
|
|
notes = models.TextField(blank=True, default="")
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
ordering = ["-updated_at"]
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.company_name} - {self.position_title}"
|
|
|
|
|
|
class JobUpdate(models.Model):
|
|
job_application = models.ForeignKey(
|
|
JobApplication,
|
|
on_delete=models.CASCADE,
|
|
related_name="updates",
|
|
)
|
|
from_status = models.CharField(
|
|
max_length=20,
|
|
choices=StatusChoices.choices,
|
|
null=True,
|
|
blank=True,
|
|
)
|
|
to_status = models.CharField(
|
|
max_length=20,
|
|
choices=StatusChoices.choices,
|
|
)
|
|
notes = models.TextField(blank=True, default="")
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
# Store metrics as JSON at update time for historical accuracy
|
|
metrics = models.JSONField(default=dict, blank=True)
|
|
|
|
class Meta:
|
|
ordering = ["-created_at"]
|
|
verbose_name = "Job Update"
|
|
verbose_name_plural = "Job Updates"
|
|
|
|
def __str__(self) -> str:
|
|
return f"Update #{self.id}: {self.job_application.company_name} → {self.to_status}" |