diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..cb46a21 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..5c3c750 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..26ee8f4 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..80b8c10 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,23 @@ from django.contrib import admin +from .models import Worker, Project, Team, WorkLog -# Register your models here. +@admin.register(Worker) +class WorkerAdmin(admin.ModelAdmin): + list_display = ('name', 'id_no', 'phone_no', 'monthly_salary', 'day_rate') + search_fields = ('name', 'id_no', 'phone_no') + +@admin.register(Project) +class ProjectAdmin(admin.ModelAdmin): + list_display = ('name', 'created_at') + search_fields = ('name',) + +@admin.register(Team) +class TeamAdmin(admin.ModelAdmin): + list_display = ('name', 'created_at') + filter_horizontal = ('workers',) + +@admin.register(WorkLog) +class WorkLogAdmin(admin.ModelAdmin): + list_display = ('date', 'project') + list_filter = ('date', 'project') + filter_horizontal = ('workers',) \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..676e74c --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,56 @@ +# Generated by Django 5.2.7 on 2026-02-03 15:47 + +import django.core.validators +import django.db.models.deletion +from decimal import Decimal +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Project', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('description', models.TextField(blank=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Worker', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('id_no', models.CharField(max_length=50, unique=True, verbose_name='ID Number')), + ('phone_no', models.CharField(max_length=20, verbose_name='Phone Number')), + ('monthly_salary', models.DecimalField(decimal_places=2, max_digits=10, validators=[django.core.validators.MinValueValidator(Decimal('0.00'))])), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Team', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('workers', models.ManyToManyField(related_name='teams', to='core.worker')), + ], + ), + migrations.CreateModel( + name='WorkLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('notes', models.TextField(blank=True)), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='core.project')), + ('workers', models.ManyToManyField(related_name='work_logs', to='core.worker')), + ], + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..9f9088d Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..524f06e 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,42 @@ from django.db import models +from django.core.validators import MinValueValidator +from decimal import Decimal -# Create your models here. +class Project(models.Model): + name = models.CharField(max_length=200) + description = models.TextField(blank=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class Worker(models.Model): + name = models.CharField(max_length=200) + id_no = models.CharField(max_length=50, unique=True, verbose_name="ID Number") + phone_no = models.CharField(max_length=20, verbose_name="Phone Number") + monthly_salary = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.00'))]) + created_at = models.DateTimeField(auto_now_add=True) + + @property + def day_rate(self): + return self.monthly_salary / Decimal('20.0') + + def __str__(self): + return self.name + +class Team(models.Model): + name = models.CharField(max_length=200) + workers = models.ManyToManyField(Worker, related_name='teams') + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class WorkLog(models.Model): + date = models.DateField() + project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='logs') + workers = models.ManyToManyField(Worker, related_name='work_logs') + notes = models.TextField(blank=True) + + def __str__(self): + return f"{self.date} - {self.project.name}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..a19c620 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,37 @@ - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}LabourFlow - Work & Payroll{% endblock %} + {% if project_description %} + + {% endif %} + {% load static %} + + + + + {% block head %}{% endblock %} - - {% block content %}{% endblock %} - + - + {% block content %}{% endblock %} + + + + \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..a4cae95 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,130 @@ -{% extends "base.html" %} +{% extends 'base.html' %} +{% load static %} -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% block title %}Dashboard | LabourFlow{% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+
+
+

Welcome Back, Admin

+

Track your projects, workers, and payroll in one place.

+
+ +
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
- -{% endblock %} \ No newline at end of file + + +
+
+ +
+
+
+
+

Active Workers

+

{{ workers_count }}

+
+
+ +
+
+
+
+
+
+
+
+

Projects

+

{{ projects_count }}

+
+
+ +
+
+
+
+
+
+
+
+

Teams

+

{{ teams_count }}

+
+
+ +
+
+
+
+
+ +
+
+
+

Recent Daily Logs

+ {% if recent_logs %} +
+ + + + + + + + + + + {% for log in recent_logs %} + + + + + + + {% endfor %} + +
DateProjectWorkersStatus
{{ log.date }}{{ log.project.name }}{{ log.workers.count }} labourersSubmitted
+
+ {% else %} +
+
+ +
+

No recent work logs found.

+ Create First Log +
+ {% endif %} +
+
+ +
+
+{% endblock %} diff --git a/core/views.py b/core/views.py index c9aed12..eb4620b 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,21 @@ import os import platform - -from django import get_version as django_version from django.shortcuts import render from django.utils import timezone - +from .models import Worker, Project, Team, WorkLog def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() - + """Render the landing screen with dashboard stats.""" + workers_count = Worker.objects.count() + projects_count = Project.objects.count() + teams_count = Team.objects.count() + recent_logs = WorkLog.objects.order_by('-date')[:5] + context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + "workers_count": workers_count, + "projects_count": projects_count, + "teams_count": teams_count, + "recent_logs": recent_logs, + "current_time": timezone.now(), } - return render(request, "core/index.html", context) + return render(request, "core/index.html", context) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..13343f9 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,81 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Poppins:wght@600;700&display=swap'); + +:root { + --primary-color: #1e293b; + --accent-color: #10b981; + --bg-color: #f1f5f9; + --text-main: #334155; + --text-light: #64748b; + --white: #ffffff; + --glass-bg: rgba(255, 255, 255, 0.7); } + +body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-color); + color: var(--text-main); + margin: 0; + padding: 0; +} + +h1, h2, h3, .heading-font { + font-family: 'Poppins', sans-serif; + font-weight: 700; +} + +.dashboard-header { + background: linear-gradient(135deg, var(--primary-color) 0%, #334155 100%); + color: var(--white); + padding: 4rem 2rem; + margin-bottom: -4rem; +} + +.card { + border: none; + border-radius: 1rem; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + transition: transform 0.2s ease-in-out; +} + +.card:hover { + transform: translateY(-5px); +} + +.stat-card { + background: var(--glass-bg); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); +} + +.btn-accent { + background-color: var(--accent-color); + color: white; + font-weight: 600; + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + border: none; +} + +.btn-accent:hover { + background-color: #059669; + color: white; +} + +.sidebar-link { + display: block; + padding: 0.75rem 1rem; + color: var(--text-main); + text-decoration: none; + border-radius: 0.5rem; + margin-bottom: 0.5rem; +} + +.sidebar-link:hover { + background-color: #e2e8f0; + color: var(--primary-color); +} + +.sidebar-link.active { + background-color: var(--primary-color); + color: var(--white); +} \ No newline at end of file