From 772d1d4c1056da27ad9adf9d9ac6724d60dc086b Mon Sep 17 00:00:00 2001 From: Ra Date: Mon, 25 Aug 2025 21:56:45 -0700 Subject: [PATCH] invite button and can navigate to submissions (no submissions will appear yet) --- functions/index.js | 62 +++++-- src/components/UiKit.tsx | 6 +- src/components/figma/FigmaEmployeeForms.tsx | 111 +++++++---- src/components/figma/FigmaQuestion.tsx | 6 +- src/components/figma/Sidebar.tsx | 173 +++++++++++++++--- .../onboarding/FigmaOnboardingComponents.tsx | 8 +- src/contexts/OrgContext.tsx | 11 +- src/pages/EmployeeQuestionnaire.tsx | 14 +- src/pages/EmployeeQuestionnaireNew.tsx | 10 +- src/pages/HelpNew.tsx | 4 +- src/pages/Login.tsx | 6 +- src/pages/Reports.tsx | 4 +- src/pages/SettingsNew.tsx | 2 +- src/pages/Submissions.tsx | 4 +- src/pages/figma/ChatAIResponse.tsx | 4 +- src/pages/figma/ChatLight.tsx | 4 +- src/services/secureApi.ts | 25 ++- src/types.ts | 12 +- 18 files changed, 334 insertions(+), 132 deletions(-) diff --git a/functions/index.js b/functions/index.js index 7a3c6fc..992f618 100644 --- a/functions/index.js +++ b/functions/index.js @@ -423,10 +423,35 @@ exports.createInvitation = onRequest({ cors: true }, async (req, res) => { // Generate invite links const baseUrl = process.env.CLIENT_URL || 'http://localhost:5173'; const inviteLink = `${baseUrl}/#/employee-form/${code}`; - const emailLink = `mailto:${email}?subject=You're invited to join our organization&body=Hi ${name},%0A%0AYou've been invited to complete a questionnaire for our organization. Please click the link below to get started:%0A%0A${inviteLink}%0A%0AThis link will expire in 7 days.%0A%0AThank you!`; + try { + if (!!process.env.SENDGRID_API_KEY) { + await fetch('https://api.sendgrid.com/v3/mail/send', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`, + }, + body: JSON.stringify({ + personalizations: [ + { + to: [{ email }], + dynamic_template_data: { + name, + inviteLink, + }, + }, + ], + from: { email: 'no-reply@auditly.com', name: 'Auditly' }, + template_id: process.env.SENDGRID_TEMPLATE_ID, + }), + }); + console.log(`📧 Invitation sent to ${email} (${name}) with code: ${code}`); + } + } catch (error) { + console.error("SendGrid email error:", error); + } // In production, send actual invitation email - console.log(`📧 Invitation sent to ${email} (${name}) with code: ${code}`); console.log(`📧 Invite link: ${inviteLink}`); res.json({ @@ -434,7 +459,6 @@ exports.createInvitation = onRequest({ cors: true }, async (req, res) => { code, employee, inviteLink, - emailLink, message: "Invitation sent successfully", }); } catch (error) { @@ -605,7 +629,7 @@ exports.submitEmployeeAnswers = onRequest({ cors: true }, async (req, res) => { const inviteDoc = inviteSnapshot.docs[0]; const invite = inviteDoc.data(); - + // Check if expired if (Date.now() > invite.expiresAt) { return res.status(400).json({ error: "Invitation has expired" }); @@ -613,21 +637,21 @@ exports.submitEmployeeAnswers = onRequest({ cors: true }, async (req, res) => { finalOrgId = invite.orgId; finalEmployeeId = invite.employee.id; - + // Consume the invitation now await inviteDoc.ref.update({ status: "consumed", consumedBy: finalEmployeeId, consumedAt: Date.now(), }); - + // Add employee to organization if not already added const employeeRef = db .collection("orgs") .doc(finalOrgId) .collection("employees") .doc(finalEmployeeId); - + const employeeDoc = await employeeRef.get(); if (!employeeDoc.exists) { await employeeRef.set({ @@ -682,13 +706,13 @@ exports.submitEmployeeAnswers = onRequest({ cors: true }, async (req, res) => { .collection("employees") .doc(finalEmployeeId) .get(); - + const employeeData = employeeDoc.exists ? employeeDoc.data() : null; - + // Get company onboarding data for LLM context const orgDoc = await db.collection("orgs").doc(finalOrgId).get(); const orgData = orgDoc.exists ? orgDoc.data() : {}; - + // Prepare company context (onboarding data) const companyContext = { name: orgData.name, @@ -699,7 +723,7 @@ exports.submitEmployeeAnswers = onRequest({ cors: true }, async (req, res) => { size: orgData.size, onboardingData: orgData // Include all org data for comprehensive context }; - + // Prepare submission data const submissionData = { employeeId: finalEmployeeId, @@ -707,7 +731,7 @@ exports.submitEmployeeAnswers = onRequest({ cors: true }, async (req, res) => { submittedAt: Date.now(), status: "completed" }; - + // Generate the report using the existing function logic let report; if (openai) { @@ -730,7 +754,7 @@ ${JSON.stringify(companyContext, null, 2)} Generate a detailed report that: 1. Evaluates how well the employee aligns with company values and culture 2. Assesses their role performance and output -3. Identifies behavioral insights and work patterns +3. Identifies behavioral insights and work patterns 4. Highlights strengths and areas for improvement 5. Provides specific recommendations for growth 6. Suggests opportunities that align with company goals @@ -835,18 +859,18 @@ Be thorough, professional, and focus on actionable insights. }, }; } - + // Store the report in Firestore const reportRef = db .collection("orgs") .doc(finalOrgId) .collection("reports") .doc(finalEmployeeId); - + await reportRef.set(report); - + console.log(`Employee report generated and stored for ${finalEmployeeId} in org ${finalOrgId}`); - + } catch (reportError) { console.error("Failed to generate employee report:", reportError); // Don't fail the submission if report generation fails @@ -1574,8 +1598,8 @@ exports.createCheckoutSession = onRequest({ cors: true }, async (req, res) => { }, ], mode: 'subscription', - success_url: `${process.env.CLIENT_URL || 'http://localhost:5174'}/#/dashboard?session_id={CHECKOUT_SESSION_ID}`, - cancel_url: `${process.env.CLIENT_URL || 'http://localhost:5174'}/#/dashboard?canceled=true`, + success_url: `${process.env.CLIENT_URL || 'http://localhost:5173'}/#/dashboard?session_id={CHECKOUT_SESSION_ID}`, + cancel_url: `${process.env.CLIENT_URL || 'http://localhost:5173'}/#/dashboard?canceled=true`, metadata: { orgId, userId: authContext.userId, diff --git a/src/components/UiKit.tsx b/src/components/UiKit.tsx index 7cbe7c4..b9a63e5 100644 --- a/src/components/UiKit.tsx +++ b/src/components/UiKit.tsx @@ -99,7 +99,7 @@ const Sidebar = () => { department: inviteForm.department }); setInviteLink(result.inviteLink); - setEmailLink(result.emailLink); + // setEmailLink(result.emailLink); setInviteForm({ name: '', email: '', role: '', department: '' }); } catch (error) { console.error('Failed to invite employee:', error); @@ -126,7 +126,7 @@ const Sidebar = () => {