| """ |
| Party/Driver Input Component |
| ============================ |
| Handles detailed party (driver) information input forms. |
| """ |
|
|
| import streamlit as st |
| from typing import Dict, Any |
|
|
|
|
| def init_party_data() -> Dict[str, Any]: |
| """Initialize empty party data structure.""" |
| return { |
| 'full_name': '', |
| 'id_iqama': '', |
| 'phone': '', |
| 'role': 'Driver', |
| 'vehicle_make_model': '', |
| 'plate_number': '', |
| 'insurance': '', |
| 'damage_notes': '', |
| 'statement': '' |
| } |
|
|
|
|
| def render_party_input(party_num: int) -> Dict[str, Any]: |
| """ |
| Render the party/driver input form. |
| |
| Args: |
| party_num: 1 or 2 to determine which party |
| |
| Returns: |
| Dictionary containing party data |
| """ |
| party_key = f'party_{party_num}' |
| |
| |
| if party_key not in st.session_state: |
| st.session_state[party_key] = init_party_data() |
| |
| color = "#FF4B4B" if party_num == 1 else "#4B7BFF" |
| |
| st.markdown(f""" |
| <div style=" |
| background: linear-gradient(135deg, {'#1a1a2e' if party_num == 1 else '#1a1a2e'} 0%, #16213e 100%); |
| border: 1px solid {color}; |
| border-radius: 10px; |
| padding: 1.5rem; |
| margin-bottom: 1rem; |
| "> |
| <h3 style="color: {color}; margin: 0 0 1rem 0;"> |
| {'π€' if party_num == 1 else 'π€'} Party {party_num} Information |
| </h3> |
| </div> |
| """, unsafe_allow_html=True) |
| |
| |
| full_name = st.text_input( |
| f"Full Name (Party {party_num})", |
| value=st.session_state[party_key].get('full_name', ''), |
| placeholder="Enter full name", |
| key=f"name_{party_num}" |
| ) |
| st.session_state[party_key]['full_name'] = full_name |
| |
| |
| col1, col2 = st.columns(2) |
| |
| with col1: |
| id_iqama = st.text_input( |
| f"ID / Iqama (Party {party_num})", |
| value=st.session_state[party_key].get('id_iqama', ''), |
| placeholder="ID or Iqama number", |
| key=f"id_{party_num}" |
| ) |
| st.session_state[party_key]['id_iqama'] = id_iqama |
| |
| with col2: |
| phone = st.text_input( |
| f"Phone (Party {party_num})", |
| value=st.session_state[party_key].get('phone', ''), |
| placeholder="+973 XXXX XXXX", |
| key=f"phone_{party_num}" |
| ) |
| st.session_state[party_key]['phone'] = phone |
| |
| |
| role = st.selectbox( |
| f"Role (Party {party_num})", |
| options=['Driver', 'Passenger', 'Pedestrian', 'Cyclist', 'Witness'], |
| index=['Driver', 'Passenger', 'Pedestrian', 'Cyclist', 'Witness'].index( |
| st.session_state[party_key].get('role', 'Driver') |
| ), |
| key=f"role_{party_num}" |
| ) |
| st.session_state[party_key]['role'] = role |
| |
| st.markdown("---") |
| st.markdown(f"**π Vehicle Information (Party {party_num})**") |
| |
| |
| vehicle = st.text_input( |
| f"Vehicle (Party {party_num})", |
| value=st.session_state[party_key].get('vehicle_make_model', ''), |
| placeholder="e.g., Toyota Camry 2022", |
| key=f"vehicle_{party_num}" |
| ) |
| st.session_state[party_key]['vehicle_make_model'] = vehicle |
| |
| col1, col2 = st.columns(2) |
| |
| with col1: |
| |
| plate = st.text_input( |
| f"Plate Number (Party {party_num})", |
| value=st.session_state[party_key].get('plate_number', ''), |
| placeholder="e.g., 12345", |
| key=f"plate_{party_num}" |
| ) |
| st.session_state[party_key]['plate_number'] = plate |
| |
| with col2: |
| |
| insurance = st.text_input( |
| f"Insurance (Party {party_num})", |
| value=st.session_state[party_key].get('insurance', ''), |
| placeholder="Company / Policy #", |
| key=f"insurance_{party_num}" |
| ) |
| st.session_state[party_key]['insurance'] = insurance |
| |
| st.markdown("---") |
| st.markdown(f"**π Damage & Statement (Party {party_num})**") |
| |
| |
| damage = st.text_area( |
| f"Damage Notes (Party {party_num})", |
| value=st.session_state[party_key].get('damage_notes', ''), |
| placeholder="e.g., front bumper, right door, headlight...", |
| height=80, |
| key=f"damage_{party_num}" |
| ) |
| st.session_state[party_key]['damage_notes'] = damage |
| |
| |
| statement = st.text_area( |
| f"Statement (Party {party_num})", |
| value=st.session_state[party_key].get('statement', ''), |
| placeholder=f"What party {party_num} says happened...", |
| height=100, |
| key=f"statement_{party_num}" |
| ) |
| st.session_state[party_key]['statement'] = statement |
| |
| return st.session_state[party_key] |
|
|
|
|
| def render_party_summary(party_num: int): |
| """Render a compact summary of party data.""" |
| party_key = f'party_{party_num}' |
| |
| if party_key not in st.session_state: |
| st.warning(f"No data for Party {party_num}") |
| return |
| |
| party = st.session_state[party_key] |
| color = "#FF4B4B" if party_num == 1 else "#4B7BFF" |
| |
| name = party.get('full_name', 'Not provided') or 'Not provided' |
| vehicle = party.get('vehicle_make_model', 'Not specified') or 'Not specified' |
| plate = party.get('plate_number', 'N/A') or 'N/A' |
| |
| st.markdown(f""" |
| <div style=" |
| background: #1a1a2e; |
| border-left: 4px solid {color}; |
| border-radius: 5px; |
| padding: 1rem; |
| margin: 0.5rem 0; |
| "> |
| <h4 style="color: {color}; margin: 0 0 0.5rem 0;">Party {party_num}</h4> |
| <p style="margin: 0.2rem 0; color: #ccc;"><b>Name:</b> {name}</p> |
| <p style="margin: 0.2rem 0; color: #ccc;"><b>Vehicle:</b> {vehicle}</p> |
| <p style="margin: 0.2rem 0; color: #ccc;"><b>Plate:</b> {plate}</p> |
| </div> |
| """, unsafe_allow_html=True) |
|
|
|
|
| def render_evidence_upload(): |
| """Render the evidence photo upload section.""" |
| |
| st.markdown(""" |
| <div style=" |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); |
| border: 1px solid #ffc107; |
| border-radius: 10px; |
| padding: 1.5rem; |
| margin: 1rem 0; |
| "> |
| <h3 style="color: #ffc107; margin: 0 0 0.5rem 0;"> |
| π· Evidence (Optional) |
| </h3> |
| <p style="color: #aaa; margin: 0;">Upload photos of the accident scene, vehicle damage, etc.</p> |
| </div> |
| """, unsafe_allow_html=True) |
| |
| |
| uploaded_files = st.file_uploader( |
| "Upload photos (optional)", |
| type=['png', 'jpg', 'jpeg'], |
| accept_multiple_files=True, |
| key="evidence_photos", |
| help="Upload accident scene photos, vehicle damage photos, etc." |
| ) |
| |
| if uploaded_files: |
| st.success(f"β
{len(uploaded_files)} photo(s) uploaded") |
| |
| |
| cols = st.columns(min(len(uploaded_files), 4)) |
| for i, file in enumerate(uploaded_files[:4]): |
| with cols[i % 4]: |
| st.image(file, caption=file.name, use_container_width=True) |
| |
| |
| st.session_state['evidence_photos'] = uploaded_files |
| else: |
| st.info("π‘ Tip: Photos can help with accident reconstruction analysis") |
| |
| return uploaded_files |
|
|
|
|
| def render_compact_party_inputs(): |
| """Render both party inputs in a compact two-column layout.""" |
| |
| col1, col2 = st.columns(2) |
| |
| with col1: |
| render_party_input(1) |
| |
| with col2: |
| render_party_input(2) |
|
|