Skip to main content
Glama

Fonoster MCP Server

Official
by fonoster
MIT License
118
7,391
  • Apple
  • Linux
verification-flow.page.tsx8.7 kB
/** * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com) * http://github.com/fonoster/fonoster * * This file is part of Fonoster * * Licensed under the MIT License (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://opensource.org/licenses/MIT * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { useState, useCallback } from "react"; import type { Route } from "./+types/verification-flow.page"; import StepProgress from "./step-progress"; import { Box } from "@mui/material"; import { Typography } from "~/core/components/design-system/ui/typography/typography"; import { VerificationFlowEmail } from "./verification-flow-email.form"; import { VerificationFlowPhone } from "./verification-flow-phone.form"; import { VerificationFlowPhoneCode } from "./verification-flow-phone-code.form"; import { useFonoster } from "~/core/sdk/hooks/use-fonoster"; import { useCurrentUser } from "~/auth/hooks/use-current-user"; import { useNavigate } from "react-router"; import { toast } from "~/core/components/design-system/ui/toaster/toaster"; import { ContactType } from "@fonoster/types"; import { getErrorMessage } from "~/core/helpers/extract-error-message"; import { useUpdateUser } from "~/auth/services/auth.service"; export function meta(_: Route.MetaArgs) { return [{ title: "Verify Account | Fonoster" }]; } export default function VerificationFlow() { const steps = [ "Verify email address", "Enter phone number", "Verify phone number" ]; const [activeStep, setActiveStep] = useState(0); const [phoneNumber, setPhoneNumber] = useState(""); const [isComplete, setIsComplete] = useState(false); const { client } = useFonoster(); const { user, userId } = useCurrentUser(); const { mutateAsync: updateUser } = useUpdateUser(); const [emailTimer, setEmailTimer] = useState(0); const [phoneTimer, setPhoneTimer] = useState(0); const startTimer = useCallback( (setTimer: React.Dispatch<React.SetStateAction<number>>) => { setTimer(30); const interval = setInterval(() => { setTimer((prev: number) => { if (prev <= 1) { clearInterval(interval); return 0; } return prev - 1; }); }, 1000); }, [] ); const handleNext = () => setActiveStep((prev) => Math.min(prev + 1, steps.length - 1)); const handleResendEmail = async () => { if (!user?.email) return; try { await client.sendVerificationCode(ContactType.EMAIL, user.email); toast("Verification code sent to your email"); startTimer(setEmailTimer); } catch (e) { toast(getErrorMessage(e)); } }; const handlePhoneSubmit = async (data: { phoneNumber: string }) => { try { await updateUser({ ref: userId, phone: data.phoneNumber }); await client.sendVerificationCode(ContactType.PHONE, data.phoneNumber); setPhoneNumber(data.phoneNumber); toast("Code sent to your phone"); handleNext(); } catch (e) { toast(getErrorMessage(e)); } }; const handlePhoneCodeSubmit = async (data: { code: string }) => { try { if (!user) { throw new Error("User not found"); } await client.verifyCode({ username: user.email, contactType: ContactType.PHONE, value: phoneNumber, verificationCode: data.code }); setIsComplete(true); toast("Phone verified! Redirecting..."); setTimeout(() => { // Redirect to home after verification window.location.href = "/"; }, 400); } catch (e) { toast(getErrorMessage(e)); } }; const handleResendPhone = async () => { if (!phoneNumber) return; try { await client.sendVerificationCode(ContactType.PHONE, phoneNumber); toast("Verification code sent to your phone"); startTimer(setPhoneTimer); } catch (e) { toast("Error sending code to phone"); } }; const emailResendSlot = ( <div style={{ textAlign: "center" }}> Didn’t receive the code?{" "} {emailTimer > 0 ? ( <span style={{ color: "#888" }}> Send again in {emailTimer} seconds </span> ) : ( <a style={{ cursor: "pointer", textDecoration: "underline" }} onClick={handleResendEmail} > Send again </a> )} </div> ); const phoneResendSlot = ( <div style={{ textAlign: "center" }}> Didn’t receive the code?{" "} {phoneTimer > 0 ? ( <span style={{ color: "#888" }}> Send again in {phoneTimer} seconds </span> ) : ( <a style={{ cursor: "pointer", textDecoration: "underline" }} onClick={handleResendPhone} > Send again </a> )} </div> ); return ( <Box sx={{ width: "100%", maxWidth: "670px", margin: "0 auto", display: "flex", flexDirection: "column", gap: "48px", flexGrow: 1, paddingY: "40px", alignItems: "center" }} > <StepProgress steps={steps} activeStep={activeStep} /> <Box sx={{ width: "100%", margin: "0 auto" }}> {activeStep === 0 && ( <Box width="100%" maxWidth="440px" gap="40px" display="flex" flexDirection="column" margin="0 auto" > <Box sx={{ display: "flex", flexDirection: "column", gap: "8px" }}> <Typography variant="heading-large" color="base.03" sx={{ textAlign: "center" }} > Verify your account </Typography> <Typography variant="body-medium" color="base.03" sx={{ textAlign: "center" }} > Please enter the verification code we’ve sent to to{" "} {user?.email} </Typography> </Box> <VerificationFlowEmail onSuccess={handleNext} resendSlot={emailResendSlot} onSendCode={() => startTimer(setEmailTimer)} /> </Box> )} {activeStep === 1 && ( <Box width="100%" maxWidth="440px" gap="40px" display="flex" flexDirection="column" margin="0 auto" > <Box sx={{ display: "flex", flexDirection: "column", gap: "8px" }}> <Typography variant="heading-large" color="base.03" sx={{ textAlign: "center" }} > Verify your account </Typography> <Typography variant="body-medium" color="base.03" sx={{ textAlign: "center" }} > For better security we require a valid phone number. </Typography> </Box> <VerificationFlowPhone onSubmit={handlePhoneSubmit} /> </Box> )} {activeStep === 2 && ( <Box width="100%" maxWidth="440px" gap="40px" display="flex" flexDirection="column" margin="0 auto" > <Box sx={{ display: "flex", flexDirection: "column", gap: "8px" }}> <Typography variant="heading-large" color="base.03" sx={{ textAlign: "center" }} > Verify your account </Typography> <Typography variant="body-medium" color="base.03" sx={{ textAlign: "center" }} > {isComplete ? "Your account has been successfully verified. Redirecting..." : "Please enter the verification code we’ve sent to to your phone"} </Typography> </Box> <VerificationFlowPhoneCode onSubmit={handlePhoneCodeSubmit} phoneNumber={phoneNumber} resendSlot={phoneResendSlot} /> </Box> )} </Box> </Box> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fonoster/fonoster'

If you have feedback or need assistance with the MCP directory API, please join our Discord server