landing page improvement and code refactor

This commit is contained in:
isra el
2023-06-19 09:10:07 +03:00
parent e27b2fb714
commit 46fdf1c35d
28 changed files with 390 additions and 191 deletions

View File

@@ -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()

View File

@@ -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=

52
web/components/Footer.tsx Normal file
View File

@@ -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 (
<Box
bg={useColorModeValue('gray.50', 'gray.900')}
color={useColorModeValue('gray.700', 'gray.200')}
>
<Container
as={Stack}
maxW={'6xl'}
py={4}
spacing={4}
justify={'center'}
align={'center'}
>
<Stack direction={'row'} spacing={6}>
<Link href='/'>Home</Link>
<Link href='/dashboard'>Dashboard</Link>
<Link href='/android'>Download App</Link>
<Link href='https://github.com/vernu/textbee'>Github</Link>
</Stack>
</Container>
<Box
borderTopWidth={1}
borderStyle={'solid'}
borderColor={useColorModeValue('gray.200', 'gray.700')}
>
<Container
as={Stack}
maxW={'6xl'}
py={4}
direction={{ base: 'column', md: 'row' }}
spacing={4}
justify='center'
align={{ base: 'center', md: 'center' }}
>
<Text>© {new Date().getFullYear()} All rights reserved</Text>
</Container>
</Box>
</Box>
)
}

View File

@@ -27,7 +27,12 @@ export default function Navbar() {
return (
<>
<Box bg={useColorModeValue('gray.100', 'gray.700')} px={4} shadow='lg' mb={1}>
<Box
bg={useColorModeValue('gray.100', 'blue.600')}
px={4}
shadow='lg'
mb={1}
>
<Flex h={16} alignItems={'center'} justifyContent={'space-between'}>
<Link href='/' passHref>
<Flex alignItems={'center'}>
@@ -37,9 +42,10 @@ export default function Navbar() {
w={'30px'}
h={'30px'}
src={'/images/sms-gateway-logo.png'}
borderRadius='full'
/>
<Box style={{ cursor: 'pointer', marginLeft: '5px' }}>
VERNU SMS
TextBee
</Box>
</Flex>
</Link>
@@ -50,6 +56,12 @@ export default function Navbar() {
{colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
</Button>
<Menu>
<Link href='https://github.com/vernu/textbee' passHref>
<MenuButton>Github</MenuButton>
</Link>
</Menu>
{!user ? (
<>
<Menu>
@@ -102,7 +114,6 @@ export default function Navbar() {
>
Dashboard
</MenuItem>
<MenuItem>Account Settings</MenuItem>
<MenuItem
onClick={() => {
dispatch(logout())

View File

@@ -64,20 +64,13 @@ const DeviceList = () => {
<Tr key={_id}>
<Td>{`${brand}/ ${model}`}</Td>
<Td>{enabled ? 'enabled' : 'disabled'}</Td>
<Td>
<EmailIcon onDoubleClick={(e) => {}} />
</Td>
<Td>{/* <EmailIcon onDoubleClick={(e) => {}} /> */}</Td>
<Td>
<Tooltip label='Double Click to delete'>
<IconButton
aria-label='Delete'
icon={<DeleteIcon />}
onDoubleClick={(e) => {
sendSMSRequest(_id, {
receivers: ['+251912657519'],
smsBody: 'Hello World',
})
}}
onDoubleClick={(e) => {}}
/>
</Tooltip>
</Td>

View File

@@ -1,4 +1,5 @@
import {
Box,
Button,
chakra,
Flex,
@@ -112,32 +113,40 @@ export default function GenerateApiKey() {
}
return (
<>
{' '}
<Flex justifyContent='center'>
<Button
/* flex={1} */
px={4}
fontSize={'sm'}
rounded={'full'}
bg={'blue.400'}
color={'white'}
boxShadow={
'0px 1px 25px -5px rgb(66 153 225 / 48%), 0 10px 10px -5px rgb(66 153 225 / 43%)'
}
_hover={{
bg: 'blue.500',
}}
_focus={{
bg: 'blue.500',
}}
onClick={generateApiKey}
disabled={generatingApiKey}
>
{generatingApiKey
? 'generating... '
: 'Generate Api Key/ Register Device'}
</Button>
</Flex>
<Box padding={5} border='1px solid gray' marginBottom={10} borderRadius='2xl'>
<Flex direction='row' justifyContent='space-between'>
{' '}
<chakra.h1
fontSize='md'
fontWeight='bold'
mt={2}
color={useColorModeValue('gray.800', 'white')}
>
Generate Api Key and Register Device
</chakra.h1>
<Button
/* flex={1} */
px={4}
fontSize={'sm'}
rounded={'full'}
bg={'blue.400'}
color={'white'}
boxShadow={
'0px 1px 25px -5px rgb(66 153 225 / 48%), 0 10px 10px -5px rgb(66 153 225 / 43%)'
}
_hover={{
bg: 'blue.500',
}}
_focus={{
bg: 'blue.500',
}}
onClick={generateApiKey}
disabled={generatingApiKey}
>
{generatingApiKey ? 'loading... ' : 'Get Started'}
</Button>
</Flex>{' '}
</Box>
{generatedApiKey && (
<>
{

View File

@@ -1,6 +1,7 @@
import {
Box,
Button,
Flex,
FormLabel,
Input,
Modal,
@@ -53,7 +54,11 @@ export default function SendSMS() {
return (
<>
<Button onClick={onOpen}>Start Sending</Button>
<Flex justifyContent='flex-end' marginBottom={20}>
<Button bg={'blue.400'} color={'white'} onClick={onOpen}>
Send SMS
</Button>
</Flex>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />

View File

@@ -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 (
<>
<Box maxW='7xl' mx={'auto'} pt={5} px={{ base: 2, sm: 12, md: 17 }}>
<chakra.h1
textAlign={'center'}
fontSize={'4xl'}
py={10}
fontWeight={'bold'}
>
Welcome {currentUser?.name}
</chakra.h1>
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={{ base: 5, lg: 8 }}>
<UserStatsCard title={'Registered '} stat={'2 devices'} />
<UserStatsCard title={'Generated'} stat={'3 API Keys'} />
<UserStatsCard title={'Sent'} stat={'100 SMS'} />
<SimpleGrid columns={{ base: 1, md: 2 }} >
<chakra.h1
textAlign={'center'}
fontSize={'4xl'}
py={10}
fontWeight={'bold'}
>
Welcome {currentUser?.name}
</chakra.h1>
<SimpleGrid columns={{ base: 3 }} spacing={{ base: 5, lg: 8 }}>
<UserStatsCard title={'Registered '} stat={`${deviceListData?.length || '-:-'} Devices`} />
<UserStatsCard title={'Generated'} stat={`${apiKeyListData?.length || '-:-'} API Keys`} />
<UserStatsCard title={'Sent'} stat={'-:- SMS'} />
</SimpleGrid>
</SimpleGrid>
</Box>
</>

View File

@@ -16,11 +16,14 @@ export default function UserStatsCard({ ...props }) {
border={'1px solid'}
borderColor={useColorModeValue('gray.800', 'gray.500')}
rounded={'lg'}
style={{
height: '90px'
}}
>
<StatLabel fontWeight={'medium'} isTruncated>
{title}
</StatLabel>
<StatNumber fontSize={'2xl'} fontWeight={'medium'}>
<StatNumber fontSize={'md'} fontWeight={'bold'}>
{stat}
</StatNumber>
</Stat>

View File

@@ -0,0 +1,42 @@
import { Box, Flex, Heading, Image, Text } from '@chakra-ui/react'
import React from 'react'
export default function CodeSnippetSection() {
return (
<Box m={{ base: 0, md: 8 }} p={{ base: 0, md: 8 }}>
<Flex
height='100%'
direction='column'
justifyContent='center'
alignItems='center'
>
<Heading fontSize={'3xl'} textAlign={'center'} py={8}>
Code Snippet
</Heading>
<Text color={'gray.600'} fontSize={'lg'} textAlign={'center'} pb='4'>
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.
</Text>
<Box
borderRadius={'lg'}
padding={{ base: 0, md: 8 }}
border={'1px solid #E2E8F0'}
w={{ base: '100%', md: '70%' }}
>
<Image
alt={'Hero Image'}
fit={'cover'}
align={'center'}
// h={'100%'}
src={
'https://ik.imagekit.io/vernu/textbee/Screenshot_2023-06-18_at_11.30.25_AM.png?updatedAt=1687077054749'
}
borderRadius={'lg'}
/>
</Box>
</Flex>
</Box>
)
}

View File

@@ -0,0 +1,88 @@
import {
Box,
Button,
chakra,
Flex,
Image,
useColorModeValue,
} from '@chakra-ui/react'
import React from 'react'
export default function DownloadAppSection() {
return (
<Box my={16}>
<Flex
padding={5}
background={useColorModeValue('gray.100', 'gray.700')}
borderRadius='2xl'
>
<Flex
borderRadius='2xl'
m={{ base: 5, md: 8 }}
p={{ base: 5, md: 8 }}
width='100%'
border='1px solid gray'
direction='row'
justifyContent='center'
>
<Box>
<Image
alt={'Hero Image'}
fit={'cover'}
align={'center'}
w={'180px'}
// h={'100%'}
src={'/images/smsgatewayandroid.png'}
/>
</Box>
<Box>
<Flex
height='100%'
direction='column'
justifyContent='center'
alignItems='center'
>
<chakra.h1
fontSize='md'
fontWeight='bold'
my={4}
color={useColorModeValue('gray.800', 'white')}
>
Download the App to get started!
</chakra.h1>
<chakra.p
fontSize='sm'
color={useColorModeValue('gray.600', 'gray.400')}
mb={4}
>
Unlock the power of messaging with our open-source Android SMS
Gateway.
</chakra.p>
<a href='/android' target='_blank'>
<Button
/* flex={1} */
px={4}
fontSize={'sm'}
rounded={'full'}
bg={'blue.400'}
color={'white'}
boxShadow={
'0px 1px 25px -5px rgb(66 153 225 / 48%), 0 10px 10px -5px rgb(66 153 225 / 43%)'
}
_hover={{
bg: 'blue.500',
}}
_focus={{
bg: 'blue.500',
}}
>
Download App
</Button>
</a>
</Flex>
</Box>
</Flex>
</Flex>
</Box>
)
}

View File

@@ -8,37 +8,46 @@ import {
SimpleGrid,
Stack,
Text,
useColorModeValue,
VStack,
} from '@chakra-ui/react'
import React from 'react'
import { featuresContent } from './featuresContent'
const FeaturesSection = () => {
return (
<Box p={4}>
<Stack spacing={4} as={Container} maxW={'6xl'}>
<Heading fontSize={'3xl'} textAlign={'center'} pb={8}>
Features
</Heading>
<Text color={'gray.600'} fontSize={'lg'} textAlign={'justify'}>
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.
</Text>
</Stack>
export default function FeaturesSection() {
const boxBgColor = useColorModeValue('gray.100', 'gray.800')
<Container maxW={'6xl'} mt={10}>
return (
<Box p={4} my={16} maxW={'6xl'}>
<Heading fontSize={'3xl'} textAlign={'center'} pb={0}>
Features
</Heading>
<Text color={'gray.600'} fontSize={'lg'} textAlign={'center'}>
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.
</Text>
<Container maxW={'6xl'} mt={0}>
<SimpleGrid columns={{ base: 1, md: 2, lg: 4 }} spacing={3} pt={16}>
{featuresContent.map((feature, i) => (
<HStack key={i} align={'top'} borderWidth="1px" borderRadius="md" p={2} shadow='lg' >
<HStack
key={i}
align={'top'}
borderWidth='1px'
borderRadius='sm'
p={2}
shadow='lg'
background={boxBgColor}
>
<Box color={'green.400'} px={1}>
<Icon as={CheckIcon} />
</Box>
<VStack align={'start'}>
<Text fontWeight={600}>{feature.title}</Text>
<Text color={'gray.600'}>{feature.description}</Text>
<Text fontWeight={800}>{feature.title}</Text>
<Text fontWeight='normal'>{feature.description}</Text>
</VStack>
</HStack>
))}
@@ -47,5 +56,3 @@ const FeaturesSection = () => {
</Box>
)
}
export default FeaturesSection

View File

@@ -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 (
<Box p={4}>
<Stack spacing={4} as={Container} maxW={'6xl'}>
<a id='#how-it-works'>
<Heading fontSize={'3xl'} textAlign={'center'} py={8}>
How It Works
</Heading>
</a>
<Text color={'gray.600'} fontSize={'lg'} textAlign={'justify'}>
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?
</Text>
</Stack>
<Box px={4} my={24} maxW={'6xl'}>
{/* @ts-ignore */}
<a name='how-it-works'>
<Heading fontSize={'3xl'} textAlign={'center'}>
How It Works
</Heading>
</a>
<Text color={'gray.600'} fontSize={'lg'} textAlign={'center'}>
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.
</Text>
<Container maxW={'6xl'} mt={10} pt={8}>
<Container maxW={'6xl'} mt={10} pt={0}>
<Accordion allowMultiple defaultIndex={[]}>
{howItWorksContent.map(({ title, description }) => (
<AccordionItem key={title}>

View File

@@ -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 (
<Container maxW={'7xl'}>
<Container maxW={'7xl'} py={8}>
<Stack
align={'center'}
spacing={{ base: 8, md: 10 }}
@@ -28,28 +40,21 @@ export default function IntroSection() {
fontWeight={600}
fontSize={{ base: '3xl', sm: '4xl', lg: '5xl' }}
>
<Text
as={'span'}
position={'relative'}
_after={{
content: "''",
width: 'full',
height: '30%',
position: 'absolute',
bottom: 1,
left: 0,
bg: 'blue.400',
zIndex: -1,
}}
>
VERNU SMS Gateway,
<Text as={'span'} position={'relative'} fontWeight={600}>
<ChatIcon /> Text
<Text as={'span'} color={'blue.400'} decoration='underline'>
Bee
</Text>
</Text>
<br />
<Text as={'span'} color={'blue.400'}>
<Text as={'span'} color={'blue.400'} fontWeight={300}>
Make your android device a portable SMS Gateway!
</Text>
</Heading>
<Text color={'gray.500'}>
<Text
color={'gray.500'}
fontSize={{ base: 'md', sm: 'lg', lg: 'xl' }}
>
Unlock the power of messaging with our open-source Android SMS
Gateway.
</Text>
@@ -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
</Button>
@@ -95,29 +98,17 @@ export default function IntroSection() {
position={'relative'}
height={'400px'}
rounded={'2xl'}
boxShadow={'2xl'}
boxShadow={'xs'}
width={'full'}
overflow={'hidden'}
>
<IconButton
aria-label={'Play Button'}
variant={'ghost'}
_hover={{ bg: 'transparent' }}
icon={<PlayIcon w={12} h={12} />}
size={'lg'}
color={'white'}
position={'absolute'}
left={'50%'}
top={'50%'}
transform={'translateX(-50%) translateY(-50%)'}
/>
<Image
alt={'Hero Image'}
fit={'cover'}
align={'center'}
w={'100%'}
h={'100%'}
src={'/images/landing-img1.jpeg'}
// w={'100%'}
// h={'100%'}
src={'/images/smsgatewayandroid.png'}
/>
</Box>
</Flex>

View File

@@ -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',
},
]

View File

@@ -3,10 +3,10 @@ import Head from 'next/head'
export default function Meta() {
return (
<Head>
<title>SMS Gateway</title>
<title>TextBee - SMS Gateway</title>
<meta name='viewport' content='initial-scale=1.0, width=device-width' />
<meta name='description' content='Android SMS Gateway' />
<meta name='keywords' content='android, sms, gateway, sms-gateway' />
<meta name='keywords' content='android, text, sms, gateway, sms-gateway' />
<meta name='author' content='Israel Abebe' />
<link rel='icon' href='/favicon.ico' />
</Head>

View File

@@ -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

View File

@@ -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

View File

@@ -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 (
<ErrorBoundary>
@@ -20,6 +21,7 @@ function MyApp({ Component, pageProps }: AppProps) {
<Wrapper>
<Component {...pageProps} />
</Wrapper>
<Footer />
</ChakraProvider>
</GoogleOAuthProvider>
</Provider>
@@ -28,7 +30,7 @@ function MyApp({ Component, pageProps }: AppProps) {
}
const Wrapper = ({ children }) => {
return <>{children}</>
return <Box minH='75vh'>{children}</Box>
}
export default MyApp

View File

@@ -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<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

View File

@@ -28,19 +28,18 @@ export default function Dashboard() {
<>
<UserStats />
<Box maxW='7xl' mx={'auto'} pt={5} px={{ base: 2, sm: 12, md: 17 }}>
<Flex justifyContent='space-evenly'>
<GenerateApiKey />
<SendSMS />
</Flex>
<Flex justifyContent='space-eve nly'></Flex>
<br />
<SimpleGrid columns={{ base: 1, md: 2 }} spacing={{ base: 5, lg: 8 }}>
<Box backdropBlur='2xl' borderWidth='1px' borderRadius='lg'>
<Box backdropBlur='2xl' borderWidth='0px' borderRadius='lg'>
<GenerateApiKey />
<ErrorBoundary>
<ApiKeyList />
</ErrorBoundary>
</Box>
<Box backdropBlur='2xl' borderWidth='1px' borderRadius='lg'>
<Box backdropBlur='2xl' borderWidth='0px' borderRadius='lg'>
<SendSMS />
<ErrorBoundary>
<DeviceList />
</ErrorBoundary>

View File

@@ -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 }) => (
<Box transform={rotate ? 'rotate(180deg)' : ''}>
<Image src={wageSvg} alt={'wave'} />
</Box>
)
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 (
<Container maxW={'7xl'}>
<IntroSection />
<Wave rotate />
<FeaturesSection />
<Wave />
<HowItWorksSection />
<Wave />
<DownloadAppSection />
<CodeSnippetSection />
</Container>
)
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View File

@@ -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<LoginResponse> => {
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<LoginResponse> => {
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<RegisterResponse> => {
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
)

View File

@@ -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

View File

@@ -1,4 +1,4 @@
export const KEY_PREFIX = 'sms0'
export const KEY_PREFIX = 'textbee'
export const LOCAL_STORAGE_KEY = {
USER: `${KEY_PREFIX}.user`,