| {`${brand}/ ${model}`} |
{enabled ? 'enabled' : 'disabled'} |
-
- {}} />
- |
+ {/* {}} /> */} |
}
- onDoubleClick={(e) => {
- sendSMSRequest(_id, {
- receivers: ['+251912657519'],
- smsBody: 'Hello World',
- })
- }}
+ onDoubleClick={(e) => {}}
/>
|
diff --git a/web/components/dashboard/GenerateApiKey.tsx b/web/components/dashboard/GenerateApiKey.tsx
index aeb48fe..970b9a9 100644
--- a/web/components/dashboard/GenerateApiKey.tsx
+++ b/web/components/dashboard/GenerateApiKey.tsx
@@ -1,4 +1,5 @@
import {
+ Box,
Button,
chakra,
Flex,
@@ -112,32 +113,40 @@ export default function GenerateApiKey() {
}
return (
<>
- {' '}
-
-
-
+
+
+ {' '}
+
+ Generate Api Key and Register Device
+
+
+ {' '}
+
{generatedApiKey && (
<>
{
diff --git a/web/components/dashboard/SendSMS.tsx b/web/components/dashboard/SendSMS.tsx
index 408265f..194bb69 100644
--- a/web/components/dashboard/SendSMS.tsx
+++ b/web/components/dashboard/SendSMS.tsx
@@ -1,6 +1,7 @@
import {
Box,
Button,
+ Flex,
FormLabel,
Input,
Modal,
@@ -53,7 +54,11 @@ export default function SendSMS() {
return (
<>
-
+
+
+
diff --git a/web/components/dashboard/UserStats.tsx b/web/components/dashboard/UserStats.tsx
index c731787..3833014 100644
--- a/web/components/dashboard/UserStats.tsx
+++ b/web/components/dashboard/UserStats.tsx
@@ -1,26 +1,34 @@
import { Box, SimpleGrid, chakra } from '@chakra-ui/react'
import React from 'react'
import { useSelector } from 'react-redux'
+import { selectApiKeyList } from '../../store/apiKeyListReducer'
import { selectAuth } from '../../store/authReducer'
+import { selectDeviceList } from '../../store/deviceListReducer'
import UserStatsCard from './UserStatsCard'
const UserStats = () => {
const { user: currentUser } = useSelector(selectAuth)
+
+ const { data: deviceListData } = useSelector(selectDeviceList)
+ const { data: apiKeyListData } = useSelector(selectApiKeyList)
+
return (
<>
-
- Welcome {currentUser?.name}
-
-
-
-
-
+
+
+ Welcome {currentUser?.name}
+
+
+
+
+
+
>
diff --git a/web/components/dashboard/UserStatsCard.tsx b/web/components/dashboard/UserStatsCard.tsx
index b0d0708..c9acbc2 100644
--- a/web/components/dashboard/UserStatsCard.tsx
+++ b/web/components/dashboard/UserStatsCard.tsx
@@ -16,11 +16,14 @@ export default function UserStatsCard({ ...props }) {
border={'1px solid'}
borderColor={useColorModeValue('gray.800', 'gray.500')}
rounded={'lg'}
+ style={{
+ height: '90px'
+ }}
>
{title}
-
+
{stat}
diff --git a/web/components/home/CodeSnippetSection.tsx b/web/components/home/CodeSnippetSection.tsx
new file mode 100644
index 0000000..6323445
--- /dev/null
+++ b/web/components/home/CodeSnippetSection.tsx
@@ -0,0 +1,42 @@
+import { Box, Flex, Heading, Image, Text } from '@chakra-ui/react'
+import React from 'react'
+
+export default function CodeSnippetSection() {
+ return (
+
+
+
+ Code Snippet
+
+
+ Send SMS messages from your web application using our REST API. You
+ can use any programming language to interact with our API. Here is a
+ sample code snippet in JavaScript using axios library.
+
+
+
+
+
+
+
+ )
+}
diff --git a/web/components/home/DownloadAppSection.tsx b/web/components/home/DownloadAppSection.tsx
new file mode 100644
index 0000000..3674da6
--- /dev/null
+++ b/web/components/home/DownloadAppSection.tsx
@@ -0,0 +1,88 @@
+import {
+ Box,
+ Button,
+ chakra,
+ Flex,
+ Image,
+ useColorModeValue,
+} from '@chakra-ui/react'
+import React from 'react'
+
+export default function DownloadAppSection() {
+ return (
+
+
+
+
+
+
+
+
+
+ Download the App to get started!
+
+
+ Unlock the power of messaging with our open-source Android SMS
+ Gateway.
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/web/components/home/FeaturesSection.tsx b/web/components/home/FeaturesSection.tsx
index 8caed05..63840d4 100644
--- a/web/components/home/FeaturesSection.tsx
+++ b/web/components/home/FeaturesSection.tsx
@@ -8,37 +8,46 @@ import {
SimpleGrid,
Stack,
Text,
+ useColorModeValue,
VStack,
} from '@chakra-ui/react'
import React from 'react'
import { featuresContent } from './featuresContent'
-const FeaturesSection = () => {
+export default function FeaturesSection() {
+ const boxBgColor = useColorModeValue('gray.100', 'gray.800')
+
return (
-
-
-
- Features
-
-
- The ultimate solution for your messaging needs! Our free open-source
- Android-based SMS Gateway provides you with all the features you need
- to effectively manage your SMS communications. From sending messages
- and automating messaging workflows via API, our SMS Gateway is the
- perfect tool for any small/mid business or individual.
-
-
+
+
+ Features
+
+
+ The ultimate solution for your messaging needs! Our free open-source
+ Android-based SMS Gateway provides you with all the features you need to
+ effectively manage your SMS communications. From sending messages and
+ automating messaging workflows via API, our SMS Gateway is the perfect
+ tool for any small/mid business or individual.
+
-
+
{featuresContent.map((feature, i) => (
-
+
- {feature.title}
- {feature.description}
+ {feature.title}
+ {feature.description}
))}
@@ -47,5 +56,3 @@ const FeaturesSection = () => {
)
}
-
-export default FeaturesSection
diff --git a/web/components/home/HowItWorksSection.tsx b/web/components/home/HowItWorksSection.tsx
index ca8884a..2a96b54 100644
--- a/web/components/home/HowItWorksSection.tsx
+++ b/web/components/home/HowItWorksSection.tsx
@@ -2,13 +2,11 @@ import { AddIcon, MinusIcon } from '@chakra-ui/icons'
import {
Accordion,
AccordionButton,
- AccordionIcon,
AccordionItem,
AccordionPanel,
Box,
Container,
Heading,
- Stack,
Text,
} from '@chakra-ui/react'
import React from 'react'
@@ -16,22 +14,20 @@ import { howItWorksContent } from './howItWorksContent'
export default function HowItWorksSection() {
return (
-
-
-
-
- How It Works
-
-
-
- Lorem ipsum dolor sit, amet consectetur adipisicing elit. Illo
- exercitationem quo quibusdam, fugit quaerat odio quisquam commodi ut?
- Aliquid ab sapiente, expedita quas neque amet consectetur quisquam
- reprehenderit voluptas commodi?
-
-
+
+ {/* @ts-ignore */}
+
+
+ How It Works
+
+
+
+ How it works is simple. You install the app on your Android device, and
+ it will turn your device into a SMS Gateway. You can then use the API to
+ send SMS messages from your own applications.
+
-
+
{howItWorksContent.map(({ title, description }) => (
diff --git a/web/components/home/IntroSection.tsx b/web/components/home/IntroSection.tsx
index e7d74be..a6df21a 100644
--- a/web/components/home/IntroSection.tsx
+++ b/web/components/home/IntroSection.tsx
@@ -7,15 +7,27 @@ import {
Text,
Button,
Image,
- IconButton,
createIcon,
} from '@chakra-ui/react'
import Link from 'next/link'
import Router from 'next/router'
+import { selectAuth } from '../../store/authReducer'
+import { useSelector } from 'react-redux'
+import { ChatIcon } from '@chakra-ui/icons'
export default function IntroSection() {
+ const { currentUser } = useSelector(selectAuth)
+
+ const handleGetStarted = () => {
+ if (!currentUser) {
+ Router.push('/register')
+ } else {
+ Router.push('/dashboard')
+ }
+ }
+
return (
-
+
-
- VERNU SMS Gateway,
+
+ Text
+
+ Bee
+
-
+
Make your android device a portable SMS Gateway!
-
+
Unlock the power of messaging with our open-source Android SMS
Gateway.
@@ -65,9 +70,7 @@ export default function IntroSection() {
colorScheme={'blue'}
bg={'blue.400'}
_hover={{ bg: 'blue.500' }}
- onClick={() => {
- Router.push('/register')
- }}
+ onClick={handleGetStarted}
>
Get Started
@@ -95,29 +98,17 @@ export default function IntroSection() {
position={'relative'}
height={'400px'}
rounded={'2xl'}
- boxShadow={'2xl'}
+ boxShadow={'xs'}
width={'full'}
overflow={'hidden'}
>
- }
- size={'lg'}
- color={'white'}
- position={'absolute'}
- left={'50%'}
- top={'50%'}
- transform={'translateX(-50%) translateY(-50%)'}
- />
diff --git a/web/components/home/howItWorksContent.ts b/web/components/home/howItWorksContent.ts
index 35e6ee8..24a38ab 100644
--- a/web/components/home/howItWorksContent.ts
+++ b/web/components/home/howItWorksContent.ts
@@ -1,23 +1,23 @@
export const howItWorksContent = [
{
- title: 'Step 1: Download The Android App',
+ title: 'Step 1: Download The Android App from textbee.vernu.dev/android',
description:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
+ '',
},
{
title: 'Step 2: Generate an API Key from the dashboard',
description:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
+ '',
},
{
title:
'Step 3: Scan the QR/ enter your api key manually and enable the gateway app',
description:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
+ '',
},
{
title: 'Step 4: Start sending',
description:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
+ 'You can now send SMS from the dashboard. or visit the API docs at https://api.textbee.vernu.dev to send SMS programatically',
},
]
diff --git a/web/components/meta/Meta.tsx b/web/components/meta/Meta.tsx
index 50f9f3a..6c90993 100644
--- a/web/components/meta/Meta.tsx
+++ b/web/components/meta/Meta.tsx
@@ -3,10 +3,10 @@ import Head from 'next/head'
export default function Meta() {
return (
- SMS Gateway
+ TextBee - SMS Gateway
-
+
diff --git a/web/lib/axiosInstance.ts b/web/lib/customAxios.ts
similarity index 70%
rename from web/lib/axiosInstance.ts
rename to web/lib/customAxios.ts
index 2d4c6d7..98d262f 100644
--- a/web/lib/axiosInstance.ts
+++ b/web/lib/customAxios.ts
@@ -1,11 +1,11 @@
import axios from 'axios'
import { LOCAL_STORAGE_KEY } from '../shared/constants'
-const axiosInstance = axios.create({
+const customAxios = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL,
})
-axiosInstance.interceptors.request.use((config) => {
+customAxios.interceptors.request.use((config) => {
const token = localStorage.getItem(LOCAL_STORAGE_KEY.TOKEN)
if (token) {
config.headers.Authorization = `Bearer ${token}`
@@ -13,4 +13,4 @@ axiosInstance.interceptors.request.use((config) => {
return config
})
-export default axiosInstance
+export default customAxios
diff --git a/web/next.config.js b/web/next.config.js
index a843cbe..4a5796b 100644
--- a/web/next.config.js
+++ b/web/next.config.js
@@ -1,6 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
+ async redirects() {
+ return [
+ {
+ source: '/android',
+ destination: 'https://appdistribution.firebase.dev/i/1439f7af2d1e8e8e',
+ permanent: false,
+ },
+ ]
+ },
}
module.exports = nextConfig
diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx
index f310872..a58f94a 100644
--- a/web/pages/_app.tsx
+++ b/web/pages/_app.tsx
@@ -2,11 +2,12 @@ import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { Provider } from 'react-redux'
import { store } from '../store/store'
-import { ChakraProvider } from '@chakra-ui/react'
+import { Box, ChakraProvider } from '@chakra-ui/react'
import Navbar from '../components/Navbar'
import Meta from '../components/meta/Meta'
import { GoogleOAuthProvider } from '@react-oauth/google'
import ErrorBoundary from '../components/ErrorBoundary'
+import Footer from '../components/Footer'
function MyApp({ Component, pageProps }: AppProps) {
return (
@@ -20,6 +21,7 @@ function MyApp({ Component, pageProps }: AppProps) {
+
@@ -28,7 +30,7 @@ function MyApp({ Component, pageProps }: AppProps) {
}
const Wrapper = ({ children }) => {
- return <>{children}>
+ return {children}
}
export default MyApp
diff --git a/web/pages/api/hello.ts b/web/pages/api/hello.ts
deleted file mode 100644
index f8bcc7e..0000000
--- a/web/pages/api/hello.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
-import type { NextApiRequest, NextApiResponse } from 'next'
-
-type Data = {
- name: string
-}
-
-export default function handler(
- req: NextApiRequest,
- res: NextApiResponse
-) {
- res.status(200).json({ name: 'John Doe' })
-}
diff --git a/web/pages/dashboard/index.tsx b/web/pages/dashboard/index.tsx
index 5f39dd7..6b0f463 100644
--- a/web/pages/dashboard/index.tsx
+++ b/web/pages/dashboard/index.tsx
@@ -28,19 +28,18 @@ export default function Dashboard() {
<>
-
-
-
-
+
-
+
+
-
+
+
diff --git a/web/pages/index.tsx b/web/pages/index.tsx
index 981f4d5..32b459f 100644
--- a/web/pages/index.tsx
+++ b/web/pages/index.tsx
@@ -1,28 +1,17 @@
-import { Box, Container } from '@chakra-ui/react'
+import { Container } from '@chakra-ui/react'
import { useGoogleOneTapLogin } from '@react-oauth/google'
-import Image from 'next/image'
-import Router from 'next/router'
-import { useEffect } from 'react'
+
import { useDispatch, useSelector } from 'react-redux'
import FeaturesSection from '../components/home/FeaturesSection'
import HowItWorksSection from '../components/home/HowItWorksSection'
import IntroSection from '../components/home/IntroSection'
import { loginWithGoogle, selectAuth } from '../store/authReducer'
-import wageSvg from '../public/images/wave.svg'
-const Wave = ({ rotate }: { rotate?: boolean }) => (
-
-
-
-)
+import DownloadAppSection from '../components/home/DownloadAppSection'
+import CodeSnippetSection from '../components/home/CodeSnippetSection'
export default function HomePage() {
- const { accessToken, user } = useSelector(selectAuth)
- useEffect(() => {
- if (accessToken && user) {
- Router.push('/dashboard')
- }
- }, [accessToken, user])
+ const { user } = useSelector(selectAuth)
const dispatch = useDispatch()
@@ -41,11 +30,10 @@ export default function HomePage() {
return (
-
-
-
+
+
)
}
diff --git a/web/public/favicon.ico b/web/public/favicon.ico
index 718d6fe..e0b4826 100644
Binary files a/web/public/favicon.ico and b/web/public/favicon.ico differ
diff --git a/web/public/images/landing-img1.jpeg b/web/public/images/landing-img1.jpeg
deleted file mode 100644
index 5f6f81a..0000000
Binary files a/web/public/images/landing-img1.jpeg and /dev/null differ
diff --git a/web/public/images/smsgatewayandroid.png b/web/public/images/smsgatewayandroid.png
new file mode 100644
index 0000000..6002480
Binary files /dev/null and b/web/public/images/smsgatewayandroid.png differ
diff --git a/web/services/index.ts b/web/services/index.ts
index 157e911..fbe7921 100644
--- a/web/services/index.ts
+++ b/web/services/index.ts
@@ -1,4 +1,4 @@
-import axiosInstance from '../lib/axiosInstance'
+import axios from '../lib/customAxios'
import {
GoogleLoginRequestPayload,
LoginRequestPayload,
@@ -11,41 +11,46 @@ import {
export const loginRequest = async (
payload: LoginRequestPayload
): Promise => {
- const res = await axiosInstance.post(`/auth/login`, payload)
+ const res = await axios.post(`/auth/login`, payload)
return res.data.data
}
export const loginWithGoogleRequest = async (
payload: GoogleLoginRequestPayload
): Promise => {
- const res = await axiosInstance.post(`/auth/google-login`, payload)
+ const res = await axios.post(`/auth/google-login`, payload)
return res.data.data
}
export const registerRequest = async (
payload: RegisterRequestPayload
): Promise => {
- const res = await axiosInstance.post(`/auth/register`, payload)
+ const res = await axios.post(`/auth/register`, payload)
+ return res.data.data
+}
+
+export const getCurrentUserRequest = async () => {
+ const res = await axios.get(`/auth/who-am-i`)
return res.data.data
}
export const generateApiKeyRequest = async () => {
- const res = await axiosInstance.post(`/auth/api-keys`, {})
+ const res = await axios.post(`/auth/api-keys`, {})
return res.data.data
}
export const getApiKeyListRequest = async () => {
- const res = await axiosInstance.get(`/auth/api-keys`)
+ const res = await axios.get(`/auth/api-keys`)
return res.data.data
}
export const deleteApiKeyRequest = async (id: string) => {
- const res = await axiosInstance.delete(`/auth/api-keys/${id}`)
+ const res = await axios.delete(`/auth/api-keys/${id}`)
return res.data.data
}
export const getDeviceListRequest = async () => {
- const res = await axiosInstance.get(`/gateway/devices`)
+ const res = await axios.get(`/gateway/devices`)
return res.data.data
}
@@ -53,7 +58,7 @@ export const sendSMSRequest = async (
deviceId: string,
payload: SendSMSRequestPayload
) => {
- const res = await axiosInstance.post(
+ const res = await axios.post(
`/gateway/devices/${deviceId}/sendSMS`,
payload
)
diff --git a/web/services/types.ts b/web/services/types.ts
index 28b15a1..b6ba53f 100644
--- a/web/services/types.ts
+++ b/web/services/types.ts
@@ -43,6 +43,10 @@ export interface LoginResponse extends BaseResponse {
export type RegisterResponse = LoginResponse
+export interface CurrentUserResponse extends BaseResponse {
+ data: UserEntity
+}
+
export interface SendSMSRequestPayload {
receivers: string[]
smsBody: string
diff --git a/web/shared/constants.ts b/web/shared/constants.ts
index 696302e..0b8113a 100644
--- a/web/shared/constants.ts
+++ b/web/shared/constants.ts
@@ -1,4 +1,4 @@
-export const KEY_PREFIX = 'sms0'
+export const KEY_PREFIX = 'textbee'
export const LOCAL_STORAGE_KEY = {
USER: `${KEY_PREFIX}.user`,