Skip to content

Commit a8e3466

Browse files
authored
Merge pull request #1 from vernu/v2
V2
2 parents b86f0cf + f37a7e7 commit a8e3466

37 files changed

+452
-206
lines changed

README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# TextBee - Android SMS Gateway
2+
3+
A simple SMS gateway that allows users to send SMS messages from a web interface or
4+
from their application via a REST API. It utilizes android phones as SMS gateways.
5+
6+
- **Technology stack**: React, Next.js, Node.js, NestJs, MongoDB, Android, Java
7+
- **Status**: MVP in development, not ready for production use yet
8+
- **Link**: [https://textbee.vernu.dev](https://textbee.vernu.dev/)
9+
10+
![](https://ik.imagekit.io/vernu/textbee/texbee-landing-light.png?updatedAt=1687076964687)
11+
12+
## Usage
13+
14+
1. Go to [textbee.vernu.dev](https://textbee.vernu.dev) and register or login with your account
15+
2. Install the app on your android phone from [textbee.vernu.dev/android](https://textbee.vernu.dev/android)
16+
3. Open the app and grant the permissions for SMS
17+
4. Go to [textbee.vernu.dev/dashboard](https://textbee.vernu.dev/dashboard) and click register device/ generate API Key
18+
5. Scan the QR code with the app or enter the API key manually
19+
6. You are ready to send SMS messages from the dashboard or from your application via the REST API
20+
21+
**Code Snippet**: Few lines of code showing how to send an SMS message via the REST API
22+
23+
```javascript
24+
const API_KEY = 'YOUR_API_KEY';
25+
const DEVICE_ID = 'YOUR_DEVICE_ID';
26+
27+
await axios.post(`https://api.textbee.vernu.dev/api/v1/devices/${DEVICE_ID}/sendSMS?apiKey=${API_KEY}`, {
28+
receivers: [ '+251912345678' ],
29+
smsBody: 'Hello World!',
30+
})
31+
32+
```
33+
34+
## Contributing
35+
36+
Contributions are welcome!
37+
38+
1. Fork the project.
39+
2. Create a feature or bugfix branch from `main` branch.
40+
3. Make sure your commit messages and PR comment summaries are descriptive.
41+
4. Create a pull request to the `main` branch.

android/.idea/.name

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "com.vernu.sms"
1111
minSdk 24
1212
targetSdk 32
13-
versionCode 5
14-
versionName "1.3.0"
13+
versionCode 7
14+
versionName "2.0"
1515

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}

android/app/src/main/java/com/vernu/sms/activities/MainActivity.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class MainActivity extends AppCompatActivity {
5454
private static final int SEND_SMS_PERMISSION_REQUEST_CODE = 0;
5555
private static final int SCAN_QR_REQUEST_CODE = 49374;
5656

57-
private static final String API_BASE_URL = "https://api.sms.vernu.dev/api/v1/";
57+
private static final String API_BASE_URL = "https://api.textbee.vernu.dev/api/v1/";
5858
private String deviceId = null;
5959

6060

@@ -89,6 +89,12 @@ protected void onCreate(Bundle savedInstanceState) {
8989
deviceIdTxt.setText(deviceId);
9090
deviceBrandAndModelTxt.setText(Build.BRAND + " " + Build.MODEL);
9191

92+
if(deviceId == null || deviceId.isEmpty()) {
93+
registerDeviceBtn.setText("Register");
94+
} else {
95+
registerDeviceBtn.setText("Update");
96+
}
97+
9298
if (isSMSPermissionGranted(mContext)) {
9399
grantSMSPermissionBtn.setEnabled(false);
94100
grantSMSPermissionBtn.setText("SMS Permission Granted");
@@ -146,7 +152,7 @@ public void onFailure(Call<RegisterDeviceResponseDTO> call, Throwable t) {
146152

147153
scanQRBtn.setOnClickListener(view -> {
148154
IntentIntegrator intentIntegrator = new IntentIntegrator(MainActivity.this);
149-
intentIntegrator.setPrompt("Go to sms.vernu.dev/dashboard and click Register Device to generate QR Code");
155+
intentIntegrator.setPrompt("Go to textbee.vernu.dev/dashboard and click Register Device to generate QR Code");
150156
intentIntegrator.setRequestCode(SCAN_QR_REQUEST_CODE);
151157
intentIntegrator.initiateScan();
152158
});

android/app/src/main/res/layout/activity_main.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<TextView
2828
android:layout_width="wrap_content"
2929
android:layout_height="wrap_content"
30-
android:text="Go to sms.vernu.dev/dashboard and click register device, then copy and paste the api key generated or scan the QR code" />
30+
android:text="Go to textbee.vernu.dev/dashboard and click register device, then copy and paste the api key generated or scan the QR code" />
3131

3232
<Button
3333
android:id="@+id/grantSMSPermissionBtn"

android/app/src/main/res/values-night/themes.xml

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
<!-- Base application theme. -->
33
<style name="Theme.SMSGateway" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
44
<!-- Primary brand color. -->
5-
<item name="colorPrimary">#f35b04</item>
6-
<item name="colorPrimaryVariant">#f18701</item>
5+
<item name="colorPrimary">#4299E1</item>
6+
<item name="colorPrimaryVariant">#4299cc</item>
77
<item name="colorOnPrimary">@color/white</item>
88
<!-- Secondary brand color. -->
9-
<item name="colorSecondary">#3d348b</item>
10-
<item name="colorSecondaryVariant">#7678ed</item>
9+
<item name="colorSecondary">#f35b04</item>
10+
<item name="colorSecondaryVariant">#f18701</item>
1111
<item name="colorOnSecondary">@color/black</item>
1212
<!-- Status bar color. -->
1313
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<resources>
2-
<string name="app_name">SMS Gateway</string>
2+
<string name="app_name">TextBee</string>
33
</resources>

android/app/src/main/res/values/themes.xml

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
<!-- Base application theme. -->
33
<style name="Theme.SMSGateway" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
44
<!-- Primary brand color. -->
5-
<item name="colorPrimary">#f35b04</item>
6-
<item name="colorPrimaryVariant">#f18701</item>
5+
<item name="colorPrimary">#4299E1</item>
6+
<item name="colorPrimaryVariant">#4299cc</item>
77
<item name="colorOnPrimary">@color/white</item>
88
<!-- Secondary brand color. -->
9-
<item name="colorSecondary">#3d348b</item>
10-
<item name="colorSecondaryVariant">#7678ed</item>
9+
<item name="colorSecondary">#f35b04</item>
10+
<item name="colorSecondaryVariant">#f18701</item>
1111
<item name="colorOnSecondary">@color/black</item>
1212
<!-- Status bar color. -->
1313
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>

android/settings.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ dependencyResolutionManagement {
1212
mavenCentral()
1313
}
1414
}
15-
rootProject.name = "SMS Gateway"
15+
rootProject.name = "TextBee"
1616
include ':app'

api/src/main.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ async function bootstrap() {
1616
})
1717

1818
const config = new DocumentBuilder()
19-
.setTitle('VERNU SMS Gateway api docs')
20-
.setDescription('api docs')
19+
.setTitle('TextBee API Docs')
20+
.setDescription('TextBee - Android SMS Gateway API Docs')
2121
.setVersion('1.0')
2222
.addBearerAuth()
2323
.build()

web/.env.example

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
NEXT_PUBLIC_API_BASE_URL=https://api.sms.vernu.dev/api/v1
1+
NEXT_PUBLIC_API_BASE_URL=https://api.textbee.vernu.dev/api/v1
22
NEXT_PUBLIC_GOOGLE_CLIENT_ID=

web/components/Footer.tsx

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
Box,
3+
chakra,
4+
Container,
5+
Stack,
6+
Text,
7+
useColorModeValue,
8+
} from '@chakra-ui/react'
9+
import Link from 'next/link'
10+
11+
export default function Footer() {
12+
return (
13+
<Box
14+
bg={useColorModeValue('gray.50', 'gray.900')}
15+
color={useColorModeValue('gray.700', 'gray.200')}
16+
>
17+
<Container
18+
as={Stack}
19+
maxW={'6xl'}
20+
py={4}
21+
spacing={4}
22+
justify={'center'}
23+
align={'center'}
24+
>
25+
<Stack direction={'row'} spacing={6}>
26+
<Link href='/'>Home</Link>
27+
<Link href='/dashboard'>Dashboard</Link>
28+
<Link href='/android'>Download App</Link>
29+
<Link href='https://github.com/vernu/textbee'>Github</Link>
30+
</Stack>
31+
</Container>
32+
33+
<Box
34+
borderTopWidth={1}
35+
borderStyle={'solid'}
36+
borderColor={useColorModeValue('gray.200', 'gray.700')}
37+
>
38+
<Container
39+
as={Stack}
40+
maxW={'6xl'}
41+
py={4}
42+
direction={{ base: 'column', md: 'row' }}
43+
spacing={4}
44+
justify='center'
45+
align={{ base: 'center', md: 'center' }}
46+
>
47+
<Text>© {new Date().getFullYear()} All rights reserved</Text>
48+
</Container>
49+
</Box>
50+
</Box>
51+
)
52+
}

web/components/Navbar.tsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ export default function Navbar() {
2727

2828
return (
2929
<>
30-
<Box bg={useColorModeValue('gray.100', 'gray.700')} px={4} shadow='lg' mb={1}>
30+
<Box
31+
bg={useColorModeValue('gray.100', 'blue.600')}
32+
px={4}
33+
shadow='lg'
34+
mb={1}
35+
>
3136
<Flex h={16} alignItems={'center'} justifyContent={'space-between'}>
3237
<Link href='/' passHref>
3338
<Flex alignItems={'center'}>
@@ -37,9 +42,10 @@ export default function Navbar() {
3742
w={'30px'}
3843
h={'30px'}
3944
src={'/images/sms-gateway-logo.png'}
45+
borderRadius='full'
4046
/>
4147
<Box style={{ cursor: 'pointer', marginLeft: '5px' }}>
42-
VERNU SMS
48+
TextBee
4349
</Box>
4450
</Flex>
4551
</Link>
@@ -50,6 +56,12 @@ export default function Navbar() {
5056
{colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
5157
</Button>
5258

59+
<Menu>
60+
<Link href='https://github.com/vernu/textbee' passHref>
61+
<MenuButton>Github</MenuButton>
62+
</Link>
63+
</Menu>
64+
5365
{!user ? (
5466
<>
5567
<Menu>
@@ -102,7 +114,6 @@ export default function Navbar() {
102114
>
103115
Dashboard
104116
</MenuItem>
105-
<MenuItem>Account Settings</MenuItem>
106117
<MenuItem
107118
onClick={() => {
108119
dispatch(logout())

web/components/dashboard/DeviceList.tsx

+2-9
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,13 @@ const DeviceList = () => {
6464
<Tr key={_id}>
6565
<Td>{`${brand}/ ${model}`}</Td>
6666
<Td>{enabled ? 'enabled' : 'disabled'}</Td>
67-
<Td>
68-
<EmailIcon onDoubleClick={(e) => {}} />
69-
</Td>
67+
<Td>{/* <EmailIcon onDoubleClick={(e) => {}} /> */}</Td>
7068
<Td>
7169
<Tooltip label='Double Click to delete'>
7270
<IconButton
7371
aria-label='Delete'
7472
icon={<DeleteIcon />}
75-
onDoubleClick={(e) => {
76-
sendSMSRequest(_id, {
77-
receivers: ['+251912657519'],
78-
smsBody: 'Hello World',
79-
})
80-
}}
73+
onDoubleClick={(e) => {}}
8174
/>
8275
</Tooltip>
8376
</Td>

web/components/dashboard/GenerateApiKey.tsx

+35-26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
Box,
23
Button,
34
chakra,
45
Flex,
@@ -112,32 +113,40 @@ export default function GenerateApiKey() {
112113
}
113114
return (
114115
<>
115-
{' '}
116-
<Flex justifyContent='center'>
117-
<Button
118-
/* flex={1} */
119-
px={4}
120-
fontSize={'sm'}
121-
rounded={'full'}
122-
bg={'blue.400'}
123-
color={'white'}
124-
boxShadow={
125-
'0px 1px 25px -5px rgb(66 153 225 / 48%), 0 10px 10px -5px rgb(66 153 225 / 43%)'
126-
}
127-
_hover={{
128-
bg: 'blue.500',
129-
}}
130-
_focus={{
131-
bg: 'blue.500',
132-
}}
133-
onClick={generateApiKey}
134-
disabled={generatingApiKey}
135-
>
136-
{generatingApiKey
137-
? 'generating... '
138-
: 'Generate Api Key/ Register Device'}
139-
</Button>
140-
</Flex>
116+
<Box padding={5} border='1px solid gray' marginBottom={10} borderRadius='2xl'>
117+
<Flex direction='row' justifyContent='space-between'>
118+
{' '}
119+
<chakra.h1
120+
fontSize='md'
121+
fontWeight='bold'
122+
mt={2}
123+
color={useColorModeValue('gray.800', 'white')}
124+
>
125+
Generate Api Key and Register Device
126+
</chakra.h1>
127+
<Button
128+
/* flex={1} */
129+
px={4}
130+
fontSize={'sm'}
131+
rounded={'full'}
132+
bg={'blue.400'}
133+
color={'white'}
134+
boxShadow={
135+
'0px 1px 25px -5px rgb(66 153 225 / 48%), 0 10px 10px -5px rgb(66 153 225 / 43%)'
136+
}
137+
_hover={{
138+
bg: 'blue.500',
139+
}}
140+
_focus={{
141+
bg: 'blue.500',
142+
}}
143+
onClick={generateApiKey}
144+
disabled={generatingApiKey}
145+
>
146+
{generatingApiKey ? 'loading... ' : 'Get Started'}
147+
</Button>
148+
</Flex>{' '}
149+
</Box>
141150
{generatedApiKey && (
142151
<>
143152
{

web/components/dashboard/SendSMS.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Box,
33
Button,
4+
Flex,
45
FormLabel,
56
Input,
67
Modal,
@@ -53,7 +54,11 @@ export default function SendSMS() {
5354

5455
return (
5556
<>
56-
<Button onClick={onOpen}>Start Sending</Button>
57+
<Flex justifyContent='flex-end' marginBottom={20}>
58+
<Button bg={'blue.400'} color={'white'} onClick={onOpen}>
59+
Send SMS
60+
</Button>
61+
</Flex>
5762

5863
<Modal isOpen={isOpen} onClose={onClose}>
5964
<ModalOverlay />

0 commit comments

Comments
 (0)