diff --git a/app.py b/app.py
index 6040f82..c50a001 100644
--- a/app.py
+++ b/app.py
@@ -2,8 +2,9 @@ import json
import os
from functools import wraps
from datetime import datetime, timedelta
+import pytz
-from flask import Flask, render_template, request, redirect, url_for, session, abort, jsonify
+from flask import Flask, render_template, request, redirect, url_for, session, abort, jsonify
from dotenv import load_dotenv
import firebase_admin
from firebase_admin import credentials, auth as fb_auth, firestore
@@ -92,6 +93,35 @@ def get_user_profile(uid: str):
return {"enabled": bool(data.get("enabled", False)), "caseEmail": data.get("caseEmail")}
+def convert_to_pacific_time(date_str):
+ """Convert UTC date string to Pacific Time and format as YYYY-MM-DD.
+
+ Args:
+ date_str (str): UTC date string in ISO 8601 format (e.g., "2025-10-24T19:20:22.377Z")
+
+ Returns:
+ str: Date formatted as YYYY-MM-DD in Pacific Time, or empty string if input is empty
+ """
+ if not date_str:
+ return ''
+
+ try:
+ # Parse the UTC datetime
+ utc_time = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
+
+ # Set timezone to UTC
+ utc_time = utc_time.replace(tzinfo=pytz.UTC)
+
+ # Convert to Pacific Time
+ pacific_time = utc_time.astimezone(pytz.timezone('America/Los_Angeles'))
+
+ # Format as YYYY-MM-DD
+ return pacific_time.strftime('%Y-%m-%d')
+ except (ValueError, AttributeError) as e:
+ print(f"[WARN] Date conversion failed for '{date_str}': {e}")
+ return ''
+
+
def fetch_all_projects():
"""Fetch all projects for a user and store them in Firestore"""
@@ -130,12 +160,12 @@ def fetch_all_projects():
lease_info_np = fetch_form(bearer, pid, "leaseInfoNP") or {}
completed_tasks = [{"description": x.get("body") ,
- "completed": x.get("completedDate")}
- for x in fetch_project_tasks(bearer, pid).get("items")
+ "completed": convert_to_pacific_time(x.get("completedDate"))}
+ for x in fetch_project_tasks(bearer, pid).get("items")
if x.get("isCompleted")]
pending_tasks = [{"description": x.get("body") ,
- "completed": x.get("completedDate")}
- for x in fetch_project_tasks(bearer, pid).get("items")
+ "completed": convert_to_pacific_time(x.get("completedDate"))}
+ for x in fetch_project_tasks(bearer, pid).get("items")
if not x.get("isCompleted")]
team = fetch_project_team(bearer, pid)
@@ -153,31 +183,31 @@ def fetch_all_projects():
), '')
# Extract notice service and expiration dates
- notice_service_date = new_file_review.get("noticeServiceDate") or ''
- notice_expiration_date = new_file_review.get("noticeExpirationDate") or ''
+ notice_service_date = convert_to_pacific_time(new_file_review.get("noticeServiceDate")) or ''
+ notice_expiration_date = convert_to_pacific_time(new_file_review.get("noticeExpirationDate")) or ''
# Extract daily rent damages
daily_rent_damages = lease_info_np.get("dailyRentDamages") or dates_and_deadlines.get("dailyRentDamages") or ''
# Extract default date
- default_date = dates_and_deadlines.get("defaultDate") or ''
- case_filed_date = dates_and_deadlines.get("dateCaseFiled") or ''
+ default_date = convert_to_pacific_time(dates_and_deadlines.get("defaultDate")) or ''
+ case_filed_date = convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled")) or ''
# Extract motion hearing dates
- demurrer_hearing_date = dates_and_deadlines.get("demurrerHearingDate") or ''
- motion_to_strike_hearing_date = dates_and_deadlines.get("mTSHearingDate") or ''
- motion_to_quash_hearing_date = dates_and_deadlines.get("mTQHearingDate") or ''
- other_motion_hearing_date = dates_and_deadlines.get("otherMotion1HearingDate") or ''
+ demurrer_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("demurrerHearingDate")) or ''
+ motion_to_strike_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("mTSHearingDate")) or ''
+ motion_to_quash_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("mTQHearingDate")) or ''
+ other_motion_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("otherMotion1HearingDate")) or ''
# Extract MSC details
- msc_date = dates_and_deadlines.get("mSCDate") or ''
- msc_time = dates_and_deadlines.get("mSCTime") or ''
+ msc_date = convert_to_pacific_time(dates_and_deadlines.get("mSCDate")) or ''
+ msc_time = dates_and_deadlines.get("mSCTime") or '' # Time field, not converting
msc_address = dates_and_deadlines.get("mSCAddress") or ''
msc_div_dept_room = dates_and_deadlines.get("mSCDeptDiv") or ''
# Extract trial details
- trial_date = dates_and_deadlines.get("trialDate") or ''
- trial_time = dates_and_deadlines.get("trialTime") or ''
+ trial_date = convert_to_pacific_time(dates_and_deadlines.get("trialDate")) or ''
+ trial_time = dates_and_deadlines.get("trialTime") or '' # Time field, not converting
trial_address = dates_and_deadlines.get("trialAddress") or ''
trial_div_dept_room = dates_and_deadlines.get("trialDeptDivRoom") or ''
@@ -185,16 +215,16 @@ def fetch_all_projects():
final_result = dates_and_deadlines.get("finalResultOfTrialMSCCa") or ''
# Extract settlement details
- date_of_settlement = dates_and_deadlines.get("dateOfStipulation") or ''
+ date_of_settlement = convert_to_pacific_time(dates_and_deadlines.get("dateOfStipulation")) or ''
final_obligation = dates_and_deadlines.get("finalObligationUnderTheStip") or ''
def_comply_stip = dates_and_deadlines.get("defendantsComplyWithStip") or ''
# Extract judgment and writ details
- judgment_date = dates_and_deadlines.get("dateOfJudgment") or ''
- writ_issued_date = dates_and_deadlines.get("writIssuedDate") or ''
+ judgment_date = convert_to_pacific_time(dates_and_deadlines.get("dateOfJudgment")) or ''
+ writ_issued_date = convert_to_pacific_time(dates_and_deadlines.get("writIssuedDate")) or ''
# Extract lockout and stay details
- scheduled_lockout = dates_and_deadlines.get("sheriffScheduledDate") or ''
+ scheduled_lockout = convert_to_pacific_time(dates_and_deadlines.get("sheriffScheduledDate")) or ''
oppose_stays = dates_and_deadlines.get("opposeStays") or ''
# Extract premises safety and entry code
@@ -202,7 +232,7 @@ def fetch_all_projects():
matter_gate_code = property_info.get("propertyEntryCodeOrInstructions") or ''
# Extract possession recovered date
- date_possession_recovered = dates_and_deadlines.get("datePossessionRecovered") or ''
+ date_possession_recovered = convert_to_pacific_time(dates_and_deadlines.get("datePossessionRecovered")) or ''
# Extract attorney fees and costs
attorney_fees = fees_and_costs.get("attorneyFeesTotal") or ''
@@ -212,7 +242,7 @@ def fetch_all_projects():
"client": c.get("firstName"),
"matter_description": p.get("projectName"),
"defendant_1": defendant_one.get('fullName', 'Unknown'),
- "matter_open": dates_and_deadlines.get("dateCaseFiled") or p.get("createdDate"),
+ "matter_open": convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled") or p.get("createdDate")),
"notice_type": new_file_review.get("noticeType", '') or '',
"case_number": dates_and_deadlines.get('caseNumber', '') or '',
"premises_address": property_info.get("premisesAddressWithUnit") or '',
@@ -254,11 +284,11 @@ def fetch_all_projects():
"attorney_fees": attorney_fees,
"costs": costs,
"documents_url": matter_overview.get('documentShareFolderURL') or '',
- "service_attempt_date_1": next(iter(service_info), {}).get('serviceDate'),
+ "service_attempt_date_1": convert_to_pacific_time(next(iter(service_info), {}).get('serviceDate')),
"contacts": cs,
"ProjectEmailAddress": p.get("projectEmailAddress"),
"Number": p.get("number"),
- "IncidentDate": (p.get("incidentDate") or detail.get("incidentDate")),
+ "IncidentDate": convert_to_pacific_time(p.get("incidentDate") or detail.get("incidentDate")),
"ProjectId": pid,
"ProjectName": p.get("projectName") or detail.get("projectName"),
"ProjectUrl": p.get("projectUrl") or detail.get("projectUrl"),
diff --git a/requirements.txt b/requirements.txt
index fd09c07..7677532 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ python-dotenv==1.0.1
requests==2.32.3
itsdangerous==2.2.0
gunicorn==23.0.0
+pytz
diff --git a/templates/base.html b/templates/base.html
index 5370bf7..d457eca 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -9,10 +9,10 @@
-
+
-
+
{% block content %}{% endblock %}
diff --git a/templates/dashboard.html b/templates/dashboard.html
index b64161f..9c053fb 100644
--- a/templates/dashboard.html
+++ b/templates/dashboard.html
@@ -1,10 +1,12 @@
{% extends 'base.html' %}
{% block content %}
-
-
Projects for {{ case_email }}
-