Global Members: Foreign Address & Phone Management

by Admin 51 views
Epic: Foreign Address & Phone Management for Members Abroad

Hey guys! This is an exciting update! We're tackling foreign address and phone management for our members living abroad. This is a big one, aimed at making the lives of our international members much easier. Let's dive in!

Status: 🟡 In Progress Branch: feature/epic-116-members-admin-ui Priority: High Target: Phase 5


Overview

So, what's this all about? We're enabling our members living abroad, or as we call them "Bý erlendis", to have separate foreign addresses and international phone numbers. This data will be securely stored in both the Django backend and Firestore. The best part? Full CRUD (Create, Read, Update, Delete) support will be available directly in the member profile UI. This means ease of use and better data management. This will make sure the foreign address and phone details are accurate and easily accessible.


Goals

Here's a breakdown of what we're aiming to achieve:

  1. Backend Support: A robust Django API with a foreign_phone field and endpoints for foreign address CRUD operations.
  2. Data Sync: Seamless Firestore synchronization that includes both foreign addresses and foreign phone numbers.
  3. UI Display: A user-friendly profile page that intelligently displays either the Icelandic OR foreign address based on the member's living status.
  4. UI Edit: Intuitive save functionality for creating and updating foreign addresses right from the UI.
  5. Validation: Strict validation for international phone numbers and postal codes to ensure data integrity.
  6. UX: A dynamic form that switches based on the "Búseta" radio selection, offering a smooth user experience. The main purpose of this is foreign address handling in the system.

Completed Work ✅

Phase 1: Display & UI Structure

Alright, let's take a look at what we've already knocked out:

  • ✅ We've added the foreign_phone field to the ContactInfo model in Django.
  • ✅ The Django migration has been deployed to production. This means we're live with the new changes!
  • ✅ The Django API serializer now includes foreign_phone and foreign_addresses. We're exposing the new data.
  • ✅ Firestore sync extracts foreign data from the Django API. Data flows smoothly.
  • ✅ A whopping 2,101 members have been synced with these new fields. That's a lot of data migration!
  • ✅ We've implemented the "Búseta" selector in the personal info card on the profile page. This is where users choose their living status.
  • ✅ Dynamic address form visibility:
    • "Bý á Íslandi" → Iceland address form
    • "Bý erlendis" → Foreign address form
    • "Heima og erlendis" → Both forms
  • ✅ We've got a country dropdown with Icelandic names (65+ countries). This is all about localization.
  • ✅ International phone formatting is in place (+354 775-8492, +45 12345678). Phones, phones everywhere!
  • ✅ CSS styling and responsive design. Because it needs to look good on all devices!
  • ✅ Tested with fake Seattle address data. Gotta make sure it works!

Commits: d72cf74c, 18ffa396, a5336d60, 72a05be7, f67ef243, fd6728bb


Remaining Work 🔄

Phase 2: Save Functionality (This Epic)

Okay, time to roll up our sleeves and get to the next phase: save functionality!

Backend (Django)

  • [ ] Issue #XXX: Create Django API endpoint for foreign address CRUD
    • POST /felagar/api/full/{member_id}/foreign-address/ - Create: This endpoint will handle the creation of new foreign address entries.
    • PUT /felagar/api/full/{member_id}/foreign-address/{id}/ - Update: This endpoint will allow users to update existing foreign address information. The {id} parameter will specify which address to modify.
    • DELETE /felagar/api/full/{member_id}/foreign-address/{id}/ - Delete: This endpoint will enable users to remove foreign address entries. Again, the {id} parameter will identify the specific address to delete.
    • current flag logic (only one current at a time): This logic will ensure that only one foreign address can be marked as the primary or "current" address for a member. This helps maintain data accuracy and avoids confusion.
    • Permissions (member edits own, admins edit all): This will implement a permission system that allows members to edit their own foreign address information, while administrators will have the ability to edit all member addresses. This ensures both user autonomy and administrative oversight.

Frontend (Ekklesia)

  • [ ] Issue #XXX: Implement save functionality in profile.js
    • Update saveChanges() to handle foreign addresses: The existing saveChanges() function in profile.js needs to be modified to accommodate the new foreign address data. This will involve adding logic to correctly process and send the data to the backend.
    • Validation for foreign phone (E.164 format): It's critical to validate the foreign phone number to ensure it adheres to the E.164 international standard. This will help prevent errors and ensure proper communication.
    • Validation for international postal codes: Each country has a unique postal code format, so we need to implement validation logic to ensure the postal code entered is valid for the selected country. This will improve data quality.
    • Optimistic Firestore update: To provide a snappy user experience, we'll implement an optimistic update to Firestore. This means the UI will reflect the changes immediately, even before the backend confirms the update.
    • Django API call for persistence: After the optimistic update, we'll make a call to the Django API to persist the changes in the database. This ensures the data is permanently stored.
    • Rollback on Django failure: In the event that the Django API call fails, we need to implement a rollback mechanism to revert the changes in Firestore and inform the user of the error. This prevents data inconsistencies.
    • Error handling and user feedback: Robust error handling is essential to gracefully handle any issues that may arise. We need to provide clear and informative feedback to the user, guiding them on how to resolve the problem.

Testing

  • [ ] Issue #XXX: End-to-end testing
    • Create foreign address: Test the functionality of creating a new foreign address entry. Verify that all fields are correctly saved and displayed.
    • Update existing foreign address: Test the ability to modify an existing foreign address. Ensure that the changes are saved correctly and reflected in the UI.
    • Delete foreign address: Test the functionality of deleting a foreign address. Verify that the address is removed from the system.
    • Switch living status: Test the behavior when the user switches their living status between "Bý á Íslandi", "Bý erlendis", and "Heima og erlendis". Ensure that the correct address form is displayed and that the data is handled appropriately.
    • Verify current flag behavior: Test the logic that ensures only one foreign address can be marked as current=true. Verify that the system correctly manages the current flag when creating or updating addresses.
    • Test rollback on API failure: Simulate a failure in the Django API and verify that the rollback mechanism correctly reverts the changes in Firestore and informs the user of the error. This is critical for data integrity.

Technical Specifications

Foreign Address Data Model (Firestore)

{
  profile: {
    phone: "775-8492",           // Iceland phone (normalized)
    foreign_phone: "+45 12345678" // International phone (E.164)
  },
  address: {                       // Iceland address
    street: "Gullengi",
    number: 37,
    postal_code: "112",
    city: "Reykjavík"
  },
  foreign_addresses: [             // Foreign addresses array
    {
      id: 456,                     // Django ID
      country: "DK",               // ISO country code
      address: "Nørrebrogade 10A",
      postal_code: "2100",
      municipality: "Copenhagen",
      current: true                // Only one can be current
    }
  ]
}

API Contract (Django)

Create Foreign Address:

POST /felagar/api/full/{member_id}/foreign-address/
Content-Type: application/json
Authorization: Token YOUR_TOKEN

{
  "country": "DK",
  "address": "Nørrebrogade 10A",
  "postal_code": "2100",
  "municipality": "Copenhagen",
  "current": true
}

Response: {"id": 123, ...}

Update Foreign Address:

PUT /felagar/api/full/{member_id}/foreign-address/{id}/
Content-Type: application/json
Authorization: Token YOUR_TOKEN

{"address": "New Address 12B"}

Response: Updated address object

Files Modified (Phase 1)

Django (Production):

  • membership/models.py - Added foreign_phone field
  • membership/serializers.py - Updated fields
  • migrations/0028_contactinfo_foreign_phone.py

Ekklesia:

  • services/members/functions/sync_members.py
  • apps/members-portal/members-area/profile.html
  • apps/members-portal/js/profile.js
  • apps/members-portal/js/utils/countries.js (new)
  • apps/members-portal/js/utils/format.js
  • apps/members-portal/i18n/values-is/strings.xml
  • apps/members-portal/styles/components/profile-edit.css

Dependencies

  • ✅ Django backend with foreign_phone field
  • ✅ Firestore sync working
  • ✅ UI structure complete
  • ⏳ Django CRUD API endpoints (needs implementation)
  • ⏳ Frontend save logic (needs implementation)

Acceptance Criteria

  • [ ] Member can create foreign address from profile page
  • [ ] Member can update their foreign address
  • [ ] Member can delete their foreign address
  • [ ] Only one foreign address can be current=true
  • [ ] Switching "Búseta" updates visible form
  • [ ] International phone validation works (E.164)
  • [ ] Postal code validation for different countries
  • [ ] Optimistic update shows changes immediately
  • [ ] Rollback works if Django API fails
  • [ ] Error messages are user-friendly (Icelandic)

Documentation

  • docs/requirements/DJANGO_FOREIGN_ADDRESS_REQUIREMENTS.md - Django implementation guide
  • apps/members-portal/js/utils/countries.js - Country code mapping
  • apps/members-portal/js/utils/format.js - International validation

Estimated Effort

  • Django CRUD API: 3-4 hours
  • Frontend save logic: 4-6 hours
  • Validation: 2-3 hours
  • Testing: 2-3 hours
  • Total: 11-16 hours

Related Epics

  • Epic #116: Functions Optimization & Security Hardening
  • Epic #43: Membership Sync with Django Backend

Created: 2025-11-03 Last Updated: 2025-11-03