Skip to content

Commit 75fe9a1

Browse files
committed
fix: speaker with contact and participation
2 parents ff7fe54 + 4ae944f commit 75fe9a1

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { useGmailDrafts, type DraftEmailOptions } from "./useGmailDrafts";
2+
import { useGoogleAuth } from "./useGoogleAuth";
3+
import { useAuthStore } from "@/stores/auth";
4+
import { useEventStore } from "@/stores/event";
5+
import { getCompanyRepresentatives } from "@/api/companies";
6+
import type { CompanyWithParticipation } from "@/dto/companies";
7+
import type {
8+
Speaker,
9+
SpeakerWithContactAndParticipation,
10+
} from "@/dto/speakers";
11+
import {
12+
EmailTemplateCategory,
13+
getVariablesFromType,
14+
loadSignature,
15+
loadTemplateAndReplace,
16+
templateCategoryTemplates,
17+
type CompanyVariablesInput,
18+
type SpeakerVariablesInput,
19+
type VariablesInput,
20+
} from "@/lib/templates";
21+
import { ref, computed } from "vue";
22+
import { getSpeakerById } from "@/api/speakers";
23+
import { Gender, Language } from "@/dto/contacts";
24+
import type { Contact } from "@/dto/contacts";
25+
26+
export type DirectEmailEntity =
27+
| CompanyWithParticipation
28+
| SpeakerWithContactAndParticipation;
29+
30+
function isSpeaker(
31+
entity: DirectEmailEntity,
32+
): entity is SpeakerWithContactAndParticipation {
33+
return (entity as Speaker).companyName !== undefined;
34+
}
35+
36+
export interface EmailWithDetails {
37+
address: string;
38+
language: Language;
39+
gender: Gender;
40+
name: string;
41+
contact: Contact;
42+
}
43+
44+
export interface SendEmailResult {
45+
success: boolean;
46+
error?: string;
47+
}
48+
49+
export const useDirectEmail = (entity: DirectEmailEntity) => {
50+
const { createDraftEmail, isLoading } = useGmailDrafts();
51+
const { signInWithGoogle, isSigningIn } = useGoogleAuth();
52+
const authStore = useAuthStore();
53+
const eventStore = useEventStore();
54+
55+
const isFetchingEmails = ref(false);
56+
const availableEmails = ref<EmailWithDetails[]>([]);
57+
const isSending = ref(false);
58+
const result = ref<SendEmailResult | null>(null);
59+
60+
const isGoogleConnected = computed(() => !!authStore.googleAccessToken);
61+
62+
const fetchAvailableEmails = async () => {
63+
isFetchingEmails.value = true;
64+
availableEmails.value = [];
65+
try {
66+
if (isSpeaker(entity)) {
67+
const response = await getSpeakerById(entity.id);
68+
const speakerData = response.data;
69+
if (speakerData.contactObject?.mails) {
70+
availableEmails.value = speakerData.contactObject.mails.map(
71+
(mail) => ({
72+
address: mail.mail,
73+
language: speakerData.contactObject.language || Language.ENGLISH,
74+
gender: speakerData.contactObject.gender || Gender.MALE,
75+
name: speakerData.name,
76+
contact: speakerData.contactObject,
77+
}),
78+
);
79+
}
80+
} else {
81+
const response = await getCompanyRepresentatives(entity.id);
82+
const representatives = response.data;
83+
availableEmails.value = representatives
84+
.filter((rep) => rep.contact?.mails && rep.contact.mails.length > 0)
85+
.map((rep) => ({
86+
address: rep.contact!.mails[0].mail,
87+
language: rep.contact!.language || Language.ENGLISH,
88+
gender: rep.contact!.gender || Gender.MALE,
89+
name: rep.name,
90+
contact: rep.contact!,
91+
}));
92+
}
93+
} catch (e) {
94+
console.error("Failed to fetch emails:", e);
95+
} finally {
96+
isFetchingEmails.value = false;
97+
}
98+
};
99+
100+
const sendEmail = async (
101+
templateCategory: EmailTemplateCategory,
102+
selectedEmails: EmailWithDetails[],
103+
): Promise<SendEmailResult> => {
104+
if (selectedEmails.length === 0) {
105+
throw new Error("No email selected.");
106+
}
107+
108+
isSending.value = true;
109+
110+
try {
111+
if (!isGoogleConnected.value) {
112+
const signInSuccess = await signInWithGoogle();
113+
if (!signInSuccess) {
114+
throw new Error("Google authentication is required.");
115+
}
116+
}
117+
118+
const signature = await loadSignature(
119+
authStore.member!,
120+
authStore.decoded,
121+
);
122+
123+
const { subject, body } = await loadTemplate(
124+
templateCategory,
125+
entity,
126+
selectedEmails[0], // Assuming template variables are based on the first selected contact
127+
);
128+
129+
const draftOptions: DraftEmailOptions = {
130+
to: selectedEmails.map((e) => e.address),
131+
subject,
132+
body: `${body}<br/>${signature}`,
133+
};
134+
135+
await createDraftEmail(draftOptions);
136+
137+
const sendResult = { success: true };
138+
result.value = sendResult;
139+
return sendResult;
140+
} catch (e) {
141+
const errorMsg = e instanceof Error ? e.message : "Unknown error";
142+
result.value = { success: false, error: errorMsg };
143+
return result.value;
144+
} finally {
145+
isSending.value = false;
146+
}
147+
};
148+
149+
const loadTemplate = async (
150+
templateCategory: EmailTemplateCategory,
151+
entity: DirectEmailEntity,
152+
email: EmailWithDetails,
153+
): Promise<{ subject: string; body: string }> => {
154+
const template =
155+
templateCategoryTemplates[templateCategory][
156+
email.language || Language.ENGLISH
157+
];
158+
const varsInput: VariablesInput = {
159+
event: eventStore.selectedEvent!,
160+
member: authStore.member!,
161+
};
162+
163+
const variables = isSpeaker(entity)
164+
? getVariablesFromType<SpeakerVariablesInput>({
165+
...varsInput,
166+
speaker: entity,
167+
})
168+
: getVariablesFromType<CompanyVariablesInput>({
169+
...varsInput,
170+
company: entity,
171+
});
172+
173+
return await loadTemplateAndReplace(template, variables);
174+
};
175+
176+
return {
177+
isFetchingEmails,
178+
availableEmails,
179+
isSending: computed(
180+
() => isSending.value || isLoading.value || isSigningIn.value,
181+
),
182+
result,
183+
fetchAvailableEmails,
184+
sendEmail,
185+
};
186+
};

0 commit comments

Comments
 (0)