Skip to main content

Communications Hub My Workspace

Communications Hub - My Workspace

Route / navigation: Browser path `/my-workspace` (PageView my-workspace). Tool selection: Zustand `workspaceTool` (WorkspaceTool in src/store/types.ts). Rendered by WorkspacePage in PageRouter.tsx.

Overview

The Communications Hub is accessible via the My Workspace sidebar item. It provides direct messaging, calendar, notes, contacts, board meetings, and related tools, with role-based access and (for messaging) real-time updates.

Feature Summary

  • Sidebar Item: "My Workspace" (directly below Dashboard; visible to all users, tools inside are paywalled for free tier)
  • Tools (7 total):
  • Messenger: Direct messaging between organization members (Plus+)
  • Video Conferencing: Schedule and manage video meetings with AI transcription (Plus+)
  • My Files: Secure file sharing with team and external contacts (Plus+)
  • Contacts: Manage business contacts and partners (Free)
  • My Calendar: Schedule events, manage availability, share public booking links, and open external group polls (Doodle) from the toolbar (Free). Event times are rendered timezone-aware from workspace_events.event_date + time fields + timezone, and builder validation enforces end-after-start plus positive whole-number signup limits.
  • Notes: Create, organize, and share notes with your team (Free)
  • Board Meetings: Governance workflow for meeting records, agenda, attendance/quorum, motions, minutes approval, transcript context, and template presentations (Plus+ recommended for linked meeting workflows)
  • Access Control: Hub accessible to all positions (including custom base). Individual tools paywalled per TOOL_MINIMUM_TIER.
  • Real-time: Uses Supabase Realtime for live message updates
  • i18n: All strings use t('workspace.*') keys (Mar 2026)

Related Docs

Data scoping (user vs organization)

Not every tool is purely user-level. The hub is “personal workspace” UX, but some features still filter or attribute data by the header entity (selectedEntity).

| Tool | Primary scope | Notes |
|------|----------------|-------|
| **Messenger** | Conversation / user | Threads are between users; eligibility rules are org-tree–aware. |
| **My Files** | **User + org metadata** | Storage path is `{userId}/…` (user-scoped bucket). **Table RLS** (post JWT migration): inserts require `organization_id` to match `jwt_org_ids()` for fund users, or `jwt_is_parent_org_admin()` for parent org admins. The UI resolves the workspace header entity → `getActualOrgId(selectedEntity)` and passes it on upload/folder create. |
| **Contacts** | **User** | `contacts` RLS: `user_id = auth.uid()`. `organization_id` nullable; no list filter by entity. |
| **Notes** | **User + shared** | Owner notes/folders are keyed by creator `userId`; shared notes are included via `workspace_note_shares`. Root view shows owner root notes plus all shared notes (including shared notes filed in owner-private folders). Folder views show owner notes in that folder only. Share picker resolves org context via `selectedEntity` → `getOrgId()` / `getActualOrgId()` / `getParentOrgId()`. |
| **Board Meetings** | **Organization** (via entity) | `board_meetings.organization_id` is required. UI resolves org scope from selected workspace entity (`getActualOrgId`). Optional transcript context links to `meetings.id`. |
| **My Calendar** | **Mixed** | Default list uses `getOrgId(selectedEntity)` → `organization_id`. **Team** view (fund/org selected): loads `organization_users` for that org, then all `workspace_events` with that `organization_id` and `created_by` in that member set (not limited to `is_team_visible`). Requires RLS policy `workspace_events_select_org_fund_members`. Parent / no-org header falls back to legacy `is_team_visible` team filter. |
| **Video Conferencing** | **Organization** (via entity) | `fetchMeetings(selectedEntity)` filters `meetings.organization_id` when org resolved; admin view can broaden. |

If the product goal is “everything user-level,” Calendar and Video are the main gaps today.

Architecture

Frontend Structure

src/features/workspace/
├── index.ts                      # Feature exports
├── components/
│   ├── WorkspacePage.tsx         # Main hub page with HubGrid
│   ├── Calendar/
│   │   ├── WorkspaceCalendarManager.tsx
│   │   ├── WorkspaceEventBuilder.tsx
│   │   ├── WorkspaceEventDetail.tsx
│   │   ├── PublicSchedulingSettings.tsx
│   │   ├── PublicSchedulingPage.tsx
│   │   └── PublicCalendarEventPage.tsx
│   ├── Messenger.tsx             # Messenger tool container
│   ├── ConversationList.tsx      # Sidebar list of conversations
│   ├── MessageThread.tsx         # Active conversation view
│   ├── MessageInput.tsx          # Message composer with attachments
│   ├── MessageBubble.tsx         # Individual message display
│   ├── NewConversationSheet.tsx  # Start new conversation sheet
│   └── MessengerDropdown.tsx     # Header dropdown for quick messaging
├── hooks/
│   ├── useConversations.ts       # Fetch/manage conversations
│   ├── useMessages.ts            # Fetch/send messages
│   ├── useRealtimeMessages.ts    # Supabase realtime subscription
│   ├── useMessagingPermissions.ts # Check eligible recipients
│   ├── useUnreadMessageCount.ts  # Unread badge count (realtime)
│   └── useMessageReactions.ts    # Emoji reactions (realtime)
├── utils/
│   └── resolveUserName.ts        # Shared name resolver (email fallback)
└── types/
    └── messaging.ts              # TypeScript types

Public Scheduling (Calendly-style)

  • Staff settings UI: src/features/workspace/components/Calendar/PublicSchedulingSettings.tsx
  • Public route: /schedule/:orgIdPrefix/:orgSlug/:userSlug where the first segment is the canonical public_org_key for newly emitted links and a legacy UUID prefix for older links.
  • Public event signup route: /calendar/:slug (workspace event signup + confirmation flow).
  • Security note: frontend calendar integration reads only non-secret metadata (connection/sync state). OAuth tokens remain server-side.

Group scheduling (Doodle-style)

  • Phase 1: Toolbar link in WorkspaceCalendarManager opens Doodle in a new tab; see 04-GROUP-SCHEDULING-DOODLE.md.
  • Phase 2 (planned): Native polls — schema and edge functions described in the same doc.
  • Public page component: src/features/workspace/components/Calendar/PublicSchedulingPage.tsx
  • Edge functions:
  • get-public-availability (load public page config + availability)
  • book-scheduling-slot (validate + create booking)
  • DB module: src/lib/db/workspace-calendar.ts (fetchPublicCalendarSettings, upsertPublicCalendarSettings)

Database Schema

Four new tables were created:

1. `conversations` - Direct message threads between two users 2. `messages` - Individual messages within conversations 3. `message_attachments` - File attachment metadata 4. `conversation_read_status` - Tracks unread counts per user

RLS Policies

  • Users can only see conversations they participate in
  • Directors (parent_org admins) can see all conversations within their org scope
  • Users can only send messages in conversations they're part of
  • Users can only soft-delete their own messages

Paywall Logic

The "My Workspace" sidebar item is visible to all users regardless of tier. Individual tools use TOOL_MINIMUM_TIER / FREE_TIER_PAYWALLED_TOOLS (e.g. Messenger, Video, My Files are Plus+; Contacts, Calendar, Notes are not paywalled the same way—see src/lib/permissions.ts).

Implementation:

  • my-workspace is NOT in FREE_TIER_PAYWALLED_HUBS
  • Several workspace tools ARE in FREE_TIER_PAYWALLED_TOOLS (not only Messenger)
  • Free users see the hub but get a paywall modal when opening a paywalled tool

Role-Based Messaging Rules

Fund Users (fund_user role)

Can only message: 1. Users in their parent organization 2. Other users within their same fund

Parent Org Users (parent_org role)

Can message anyone within their organizational scope (all funds under their parent org).

Key Components

WorkspacePage

Main hub page using the standard HubGrid pattern with PageHeader. Shows available tools as tiles with paywall badges for free users.

Messenger

Container component managing:

  • Conversation list sidebar
  • Message thread view
  • New conversation creation
  • Mobile responsive layout (stacked view on mobile)

NewConversationSheet

Sheet component for starting new conversations:

  • Fetches eligible recipients via get_eligible_message_recipients() RPC
  • Searchable list with user avatars and org info
  • Creates conversation on selection

MessageBubble

Individual message display with:

  • Sender avatar and name (resolved via resolveUserName with email fallback)
  • Message content with attachments
  • Emoji reactions (click bubble to react)
  • Timestamp

Database Migrations

20260202_messenger_tables.sql

Creates the four messaging tables with:

  • Proper foreign key constraints
  • Indexes for performance
  • RLS policies for security
  • Triggers for updated_at and unread count management

20260202_messenger_functions.sql

Helper functions:

  • validate_messaging_permission() - Validates if sender can message recipient
  • get_eligible_message_recipients() - Returns list of users a user can message
  • get_conversation_participants() - Returns both participants of a conversation

20260202_message_notifications.sql

Notification trigger:

  • Creates in-app notifications when new messages are sent
  • Notifies the recipient (not the sender)
  • Links to the conversation in My Workspace

Notifications

New message notifications use the existing notification system:

  • Type: new_message
  • Title: "New message from {sender_name}"
  • Message: Preview of message content (truncated to 100 chars)
  • Link: /my-workspace?conversation={conversation_id}

Attachments

Supported File Types

  • Images: jpg, png, gif, webp
  • Documents: pdf, doc, docx, xls, xlsx
  • Text: txt, csv

Limits

  • Max file size: 50MB
  • Max attachments per message: 5

Storage

Files are stored in the message-attachments Supabase Storage bucket with path structure:

{user_id}/{conversation_id}/{timestamp}_{random}_{filename}

Mobile Responsiveness

  • Desktop (>768px): Side-by-side layout with conversation list and thread
  • Mobile (<768px): Stacked layout with navigation between list and thread views
  • Back button appears on mobile when viewing a conversation

Error Handling

  • Error states displayed with retry buttons
  • Graceful degradation if attachments fail to load
  • Toast notifications for send/delete failures

Future Enhancements

Potential additions for future releases:

  • Typing indicators
  • Voice/video calls
  • Read receipts

Files Modified

New Files

  • src/features/workspace/ - Entire feature folder
  • backend/migrations/20260202_messenger_*.sql - Database migrations

Modified Files

  • src/lib/permissions.ts - Added my-workspace to HubId, messenger to paywalled tools
  • src/store/types.ts - Added my-workspace to PageView type
  • src/components/shared/AppSidebar.tsx - Added My Workspace sidebar item
  • src/App.tsx - Added routing for my-workspace page
  • src/i18n/locales/en/common.json - Added translation key
  • src/lib/imageUtils.ts - Added attachment upload utilities

Synced from IFMmvp-Frontend documentation: workspace/00-WORKSPACE-HUB.md

Ready to Get Started?

See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.

Questions? Email us at steven@getalignmint.org

Ready to get started?Start Plus Trial