From 46fdf1c35d9fcd408c7f3e1a4288f4a4e420a126 Mon Sep 17 00:00:00 2001 From: isra el Date: Mon, 19 Jun 2023 09:10:07 +0300 Subject: [PATCH] landing page improvement and code refactor --- api/src/main.ts | 4 +- web/.env.example | 2 +- web/components/Footer.tsx | 52 +++++++++++ web/components/Navbar.tsx | 17 +++- web/components/dashboard/DeviceList.tsx | 11 +-- web/components/dashboard/GenerateApiKey.tsx | 61 +++++++------ web/components/dashboard/SendSMS.tsx | 7 +- web/components/dashboard/UserStats.tsx | 32 ++++--- web/components/dashboard/UserStatsCard.tsx | 5 +- web/components/home/CodeSnippetSection.tsx | 42 +++++++++ web/components/home/DownloadAppSection.tsx | 88 +++++++++++++++++++ web/components/home/FeaturesSection.tsx | 47 +++++----- web/components/home/HowItWorksSection.tsx | 30 +++---- web/components/home/IntroSection.tsx | 67 ++++++-------- web/components/home/howItWorksContent.ts | 10 +-- web/components/meta/Meta.tsx | 4 +- web/lib/{axiosInstance.ts => customAxios.ts} | 6 +- web/next.config.js | 9 ++ web/pages/_app.tsx | 6 +- web/pages/api/hello.ts | 13 --- web/pages/dashboard/index.tsx | 11 ++- web/pages/index.tsx | 26 ++---- web/public/favicon.ico | Bin 25931 -> 15406 bytes web/public/images/landing-img1.jpeg | Bin 24226 -> 0 bytes web/public/images/smsgatewayandroid.png | Bin 0 -> 247983 bytes web/services/index.ts | 23 +++-- web/services/types.ts | 4 + web/shared/constants.ts | 2 +- 28 files changed, 389 insertions(+), 190 deletions(-) create mode 100644 web/components/Footer.tsx create mode 100644 web/components/home/CodeSnippetSection.tsx create mode 100644 web/components/home/DownloadAppSection.tsx rename web/lib/{axiosInstance.ts => customAxios.ts} (70%) delete mode 100644 web/pages/api/hello.ts delete mode 100644 web/public/images/landing-img1.jpeg create mode 100644 web/public/images/smsgatewayandroid.png diff --git a/api/src/main.ts b/api/src/main.ts index 0c0623b..83abe89 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -16,8 +16,8 @@ async function bootstrap() { }) const config = new DocumentBuilder() - .setTitle('VERNU SMS Gateway api docs') - .setDescription('api docs') + .setTitle('TextBee API Docs') + .setDescription('TextBee - Android SMS Gateway API Docs') .setVersion('1.0') .addBearerAuth() .build() diff --git a/web/.env.example b/web/.env.example index e947137..8352dcd 100644 --- a/web/.env.example +++ b/web/.env.example @@ -1,2 +1,2 @@ -NEXT_PUBLIC_API_BASE_URL=https://api.sms.vernu.dev/api/v1 +NEXT_PUBLIC_API_BASE_URL=https://api.textbee.vernu.dev/api/v1 NEXT_PUBLIC_GOOGLE_CLIENT_ID= \ No newline at end of file diff --git a/web/components/Footer.tsx b/web/components/Footer.tsx new file mode 100644 index 0000000..1053f57 --- /dev/null +++ b/web/components/Footer.tsx @@ -0,0 +1,52 @@ +import { + Box, + chakra, + Container, + Stack, + Text, + useColorModeValue, +} from '@chakra-ui/react' +import Link from 'next/link' + +export default function Footer() { + return ( + + + + Home + Dashboard + Download App + Github + + + + + + © {new Date().getFullYear()} All rights reserved + + + + ) +} diff --git a/web/components/Navbar.tsx b/web/components/Navbar.tsx index 02ea415..aae6412 100644 --- a/web/components/Navbar.tsx +++ b/web/components/Navbar.tsx @@ -27,7 +27,12 @@ export default function Navbar() { return ( <> - + @@ -37,9 +42,10 @@ export default function Navbar() { w={'30px'} h={'30px'} src={'/images/sms-gateway-logo.png'} + borderRadius='full' /> - VERNU SMS + TextBee @@ -50,6 +56,12 @@ export default function Navbar() { {colorMode === 'light' ? : } + + + Github + + + {!user ? ( <> @@ -102,7 +114,6 @@ export default function Navbar() { > Dashboard - Account Settings { dispatch(logout()) diff --git a/web/components/dashboard/DeviceList.tsx b/web/components/dashboard/DeviceList.tsx index fb85546..0b4b182 100644 --- a/web/components/dashboard/DeviceList.tsx +++ b/web/components/dashboard/DeviceList.tsx @@ -64,20 +64,13 @@ const DeviceList = () => { {`${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. + + + + {'Hero + + + + ) +} 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 ( + + + + + {'Hero + + + + + 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%)'} - /> {'Hero
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) { +