Skip to content

feat(dialer): volunteer caller frontend (Telnyx WebRTC UI) - #207

Merged
sukhada merged 3 commits into
dialer-backend-2from
dialer-fe-webrtc
Jun 16, 2026
Merged

feat(dialer): volunteer caller frontend (Telnyx WebRTC UI) #207
sukhada merged 3 commits into
dialer-backend-2from
dialer-fe-webrtc

Conversation

@sukhada

@sukhada sukhada commented Jun 14, 2026

Copy link
Copy Markdown

No description provided.

ajohn25 and others added 2 commits June 14, 2026 10:51
Frontend for the volunteer dialer, stacked on dialer-backend:
- VolunteerDialer container: WebRTC call controls, timer, status bar,
  disposition form, contact flow
- TexterTodoList: call-shift request entry point (CallRequest) and
  call-aware assignment summary
- AdminCampaignStats: call-campaign stat tweaks
- dialer GraphQL operations (hooks) and @telnyx/webrtc dependency

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sukhada
sukhada requested a review from ajohn25 June 16, 2026 14:20
* feat(dialer): add canned responses + tags to calling

* feat(dialer): allow releasing calls (#209)

* feat(dialer): allow releasing calls

* feat(dialer): add texting history to call screen (#210)

* feat(dialer): add texting history to call screen

* chore: update seeds to not use logger.info

* chore(dialer): fix variable interpolation in script
@sukhada
sukhada merged commit f14a017 into dialer-backend-2 Jun 16, 2026
5 checks passed
@sukhada
sukhada deleted the dialer-fe-webrtc branch June 16, 2026 15:30
sukhada added a commit that referenced this pull request Jun 16, 2026
* feat(dialer): volunteer caller backend (Design-B call tracking)

Backend for the volunteer dialer, stacked on dialer-campaign-type:
- GraphQL schema, resolvers, and Telnyx WebRTC token route
- dialer lib: shift assignment, contact-hours-aware serving, atomic
  call_status claim, disposition + attempt tracking
- forward migrations (campaign-type's create migrations left untouched):
  - 000009: drop call_campaigns_no_autoassign (call campaigns use autoassign
    for shifts)
  - 000010: add call_status/attempt_count/last_attempted_at to
    dialer_campaign_contact and disposition to dialer_call

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(dialer): address feedback

* feat(dialer): volunteer caller frontend (Telnyx WebRTC UI)  (#207)

* chore(tool-versions): update node version (#195)

* feat(dialer): volunteer caller frontend (Telnyx WebRTC UI)

Frontend for the volunteer dialer, stacked on dialer-backend:
- VolunteerDialer container: WebRTC call controls, timer, status bar,
  disposition form, contact flow
- TexterTodoList: call-shift request entry point (CallRequest) and
  call-aware assignment summary
- AdminCampaignStats: call-campaign stat tweaks
- dialer GraphQL operations (hooks) and @telnyx/webrtc dependency

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(dialer): add canned responses + tags to calling (#208)

* feat(dialer): add canned responses + tags to calling

* feat(dialer): allow releasing calls (#209)

* feat(dialer): allow releasing calls

* feat(dialer): add texting history to call screen (#210)

* feat(dialer): add texting history to call screen

* chore: update seeds to not use logger.info

* chore(dialer): fix variable interpolation in script

---------

Co-authored-by: Aashish John <aashishjohn25@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Aashish John <aashishjohn25@gmail.com>
hideIfZero: true
})}
{isCallCampaign ? (
<Button

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: We could probs show a badge with the number of calls left in the assignment as an indicator of their progress?

// The Telnyx SDK attaches the remote party's audio stream to this element
// and plays it; without a remoteElement there is no audio output.
useEffect(() => {
const audio = document.createElement("audio");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is it possible to do something like <audio ref={remoteAudioRef} in JSX to give React control over this instead?

const clientRef = useRef<TelnyxRTC | null>(null);
const activeCallRef = useRef<Call | null>(null);
const remoteAudioRef = useRef<HTMLAudioElement | null>(null);
const wasAnsweredRef = useRef(false);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Seems like this isn't read anywhere? Could it be removed?

setActiveCall(call);

// Map Telnyx numeric state to our display state
const stateLabel: string = (call as any).state ?? "";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Looks like this satisfies TS without going to any

const stateLabel: string = (call).state ?? "";

case "hangup":
case "destroy":
case "purge":
setCallEndCause((call as any).cause ?? null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Looks like this satisfies TS without going to any
setCallEndCause((call).cause ?? null);

Comment on lines +91 to +92
activeCallRef.current = call;
setActiveCall(call);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Should these only happen for requesting/trying/ringing/active ?

Comment on lines +43 to +47
assignableFilter:
"and do_not_call = false and call_status in ('not_attempted', 'no_answer')",
// Prioritize never-attempted contacts over no-answer retries.
assignableOrder:
"(case when call_status = 'not_attempted' then 10 else 20 end) asc"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: I think retries should be opted into by admins in some way. Otherwise could we end up calling the same people over and over?

// ordering baked into the per-stage option defaults). Only call campaigns
// override the table and assignable rules.
interface ContactTableConfig {
table?: string;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required: I would define a type for the two contact tables and only accept those values wherever we're passing in a table like this. Something like

type ContactTable = "campaign_contact" | "dialer_campaign_contact"

sukhada added a commit that referenced this pull request Jun 17, 2026
* feat(campaigns): add campaign type (SMS/Call) to campaign editor

* feat(admin): add campaign type to admin UI

* feat(admin): add new dialer tables

* chore(admin): address feedback

* chore(dialer): address new table feedback

* chore(dialer): address feedback

* chore(dialer): regenerate schema dump

* chore(dialer): address feedback

* feat(dialer): volunteer caller backend  (#205)

* feat(dialer): volunteer caller backend (Design-B call tracking)

Backend for the volunteer dialer, stacked on dialer-campaign-type:
- GraphQL schema, resolvers, and Telnyx WebRTC token route
- dialer lib: shift assignment, contact-hours-aware serving, atomic
  call_status claim, disposition + attempt tracking
- forward migrations (campaign-type's create migrations left untouched):
  - 000009: drop call_campaigns_no_autoassign (call campaigns use autoassign
    for shifts)
  - 000010: add call_status/attempt_count/last_attempted_at to
    dialer_campaign_contact and disposition to dialer_call

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(dialer): address feedback

* feat(dialer): volunteer caller frontend (Telnyx WebRTC UI)  (#207)

* chore(tool-versions): update node version (#195)

* feat(dialer): volunteer caller frontend (Telnyx WebRTC UI)

Frontend for the volunteer dialer, stacked on dialer-backend:
- VolunteerDialer container: WebRTC call controls, timer, status bar,
  disposition form, contact flow
- TexterTodoList: call-shift request entry point (CallRequest) and
  call-aware assignment summary
- AdminCampaignStats: call-campaign stat tweaks
- dialer GraphQL operations (hooks) and @telnyx/webrtc dependency

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(dialer): add canned responses + tags to calling (#208)

* feat(dialer): add canned responses + tags to calling

* feat(dialer): allow releasing calls (#209)

* feat(dialer): allow releasing calls

* feat(dialer): add texting history to call screen (#210)

* feat(dialer): add texting history to call screen

* chore: update seeds to not use logger.info

* chore(dialer): fix variable interpolation in script

---------

Co-authored-by: Aashish John <aashishjohn25@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Aashish John <aashishjohn25@gmail.com>

* chore(dialer): fix down migration for campaign type campaign view

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Aashish John <aashishjohn25@gmail.com>
@ajohn25 ajohn25 mentioned this pull request Jun 18, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants