Browse Source

feat: login with pair code (#171)

* feat: wip pair code login

feat(app): add LoginWithCode method to IAppService interface for handling phone number login
feat(app): implement LoginWithCode method in App struct to handle phone number login logic
feat(app): implement LoginWithCode method in serviceApp to pair phone number with WhatsApp client

* feat: add api login with code

* feat: add ui getting pair code

* feat: add pair code

* chore: update docs & text

* feat: upgrade version

* chore: update docs

* feat: update image gallery

* fix: show error message

* chore: update repo

* fix: some code improvement
pull/181/head v4.16.0
Aldino Kemal 2 years ago
committed by GitHub
parent
commit
7eb1de0221
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      docker/golang.Dockerfile
  2. 43
      docs/openapi.yaml
  3. 52
      readme.md
  4. 2
      src/config/settings.go
  5. 1
      src/domains/app/app.go
  6. 8
      src/go.mod
  7. 8
      src/go.sum
  8. 15
      src/internal/rest/app.go
  9. 2
      src/pkg/error/app_error.go
  10. 23
      src/services/app.go
  11. 21
      src/validations/app_validation.go
  12. 61
      src/validations/app_validation_test.go
  13. 7
      src/views/components/AppLogin.js
  14. 109
      src/views/components/AppLoginWithCode.js
  15. 3
      src/views/components/AppReconnect.js
  16. 6
      src/views/index.html

4
docker/golang.Dockerfile

@ -1,7 +1,7 @@
############################
# STEP 1 build executable binary
############################
FROM golang:1.21.5-alpine3.19 AS builder
FROM golang:1.22.5-alpine3.20 AS builder
RUN apk update && apk add --no-cache gcc musl-dev gcompat
WORKDIR /whatsapp
COPY ./src .
@ -14,7 +14,7 @@ RUN go build -o /app/whatsapp
#############################
## STEP 2 build a smaller image
#############################
FROM alpine:3.19
FROM alpine:3.20
RUN apk update && apk add --no-cache ffmpeg
WORKDIR /app
# Copy compiled from builder.

43
docs/openapi.yaml

@ -1,7 +1,7 @@
openapi: 3.0.0
info:
title: WhatsApp API MultiDevice
version: 4.1.0
version: 4.2.0
description: This API is used for sending whatsapp via API
servers:
- url: http://localhost:3000
@ -36,6 +36,32 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorInternalServer'
/app/login-with-code:
get:
operationId: appLoginWithCode
tags:
- app
summary: Login with pairing code
parameters:
- name: phone
in: query
schema:
type: string
example: '628912344551'
description: Your phone number
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/LoginWithCodeResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorInternalServer'
/app/logout:
get:
operationId: appLogout
@ -1241,6 +1267,21 @@ components:
device:
type: string
example: '628960561XXX.0:64@s.whatsapp.net'
LoginWithCodeResponse:
type: object
properties:
code:
type: string
example: SUCCESS
message:
type: string
example: Success
results:
type: object
properties:
pair_code:
type: string
example: ABCD-1234
LoginResponse:
type: object
properties:

52
readme.md

@ -100,8 +100,8 @@ You can fork or edit this source code !
| Feature | Menu | Method | URL |
|---------|------------------------------|--------|-------------------------------|
| ✅ | Login | GET | /app/login |
| | Login With Pair Code | GET | /app/login-with-code |
| ✅ | Login with Scan QR | GET | /app/login |
| | Login With Pair Code | GET | /app/login-with-code |
| ✅ | Logout | GET | /app/logout |
| ✅ | Reconnect | GET | /app/reconnect |
| ✅ | Devices | GET | /app/devices |
@ -136,28 +136,32 @@ You can fork or edit this source code !
❌ = Not Available Yet
```
### App User Interface
1. Homepage ![Homepage](https://i.ibb.co.com/d05L4VX/homepage.png)
2. Login ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1)
3. Send Message ![Send Message](https://i.ibb.co.com/rc3NXMX/send-message.png?v1)
4. Send Image ![Send Image](https://i.ibb.co.com/BcFL3SD/send-image.png?v1)
5. Send File ![Send File](https://i.ibb.co.com/f4yxjpp/send-file.png)
6. Send Video ![Send Video](https://i.ibb.co.com/PrD3P51/send-video.png)
7. Send Contact ![Send Contact](https://i.ibb.co.com/4810H7N/send-contact.png)
8. Send Location ![Send Location](https://i.ibb.co.com/TWsy09G/send-location.png)
9. Send Audio ![Send Location](https://i.ibb.co.com/p1wL4wh/Send-Audio.png)
10. Send Poll ![Send Poll](https://i.ibb.co.com/mq2fGHz/send-poll.png)
11. Revoke Message ![Revoke Message](https://i.ibb.co.com/yswhvQY/revoke.png?v1)
12. Delete Message ![Delete Message](https://i.ibb.co.com/F70SZ84/image.png)
13. Reaction Message ![Revoke Message](https://i.ibb.co.com/BfHgSHG/react-message.png)
14. Edit Message ![Edit Message](https://i.ibb.co.com/kXfpqJw/update-message.png)
15. User Info ![User Info](https://i.ibb.co.com/3zjX6Cz/user-info.png?v=1)
16. User Avatar ![User Avatar](https://i.ibb.co.com/ZmJZ4ZW/search-avatar.png?v=1)
17. My Privacy ![My Privacy](https://i.ibb.co.com/Cw1sMQz/my-privacy.png)
18. My Group ![My Group](https://i.ibb.co.com/WB268Xy/list-group.png)
19. Auto Reply ![Auto Reply](https://i.ibb.co.com/D4rTytX/IMG-20220517-162500.jpg)
20. Basic Auth Prompt ![Basic Auth](https://i.ibb.co.com/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png)
### User Interface
| Description | Image |
|--------------------|------------------------------------------------------------------------------------------|
| Homepage | ![Homepage](https://i.ibb.co.com/L0B1LVb/homepage-v4-16.png) |
| Login | ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1) |
| Login With Code | ![Login With Code](https://i.ibb.co.com/rdJGvGw/paircode.png) |
| Send Message | ![Send Message](https://i.ibb.co.com/rc3NXMX/send-message.png?v1) |
| Send Image | ![Send Image](https://i.ibb.co.com/BcFL3SD/send-image.png?v1) |
| Send File | ![Send File](https://i.ibb.co.com/f4yxjpp/send-file.png) |
| Send Video | ![Send Video](https://i.ibb.co.com/PrD3P51/send-video.png) |
| Send Contact | ![Send Contact](https://i.ibb.co.com/4810H7N/send-contact.png) |
| Send Location | ![Send Location](https://i.ibb.co.com/TWsy09G/send-location.png) |
| Send Audio | ![Send Audio](https://i.ibb.co.com/p1wL4wh/Send-Audio.png) |
| Send Poll | ![Send Poll](https://i.ibb.co.com/mq2fGHz/send-poll.png) |
| Revoke Message | ![Revoke Message](https://i.ibb.co.com/yswhvQY/revoke.png?v1) |
| Delete Message | ![Delete Message](https://i.ibb.co.com/F70SZ84/image.png) |
| Reaction Message | ![Reaction Message](https://i.ibb.co.com/BfHgSHG/react-message.png) |
| Edit Message | ![Edit Message](https://i.ibb.co.com/kXfpqJw/update-message.png) |
| User Info | ![User Info](https://i.ibb.co.com/3zjX6Cz/user-info.png?v=1) |
| User Avatar | ![User Avatar](https://i.ibb.co.com/ZmJZ4ZW/search-avatar.png?v=1) |
| My Privacy | ![My Privacy](https://i.ibb.co.com/Cw1sMQz/my-privacy.png) |
| My Group | ![My Group](https://i.ibb.co.com/WB268Xy/list-group.png) |
| Auto Reply | ![Auto Reply](https://i.ibb.co.com/D4rTytX/IMG-20220517-162500.jpg) |
| Basic Auth Prompt | ![Basic Auth Prompt](https://i.ibb.co.com/PDjQ92W/Screenshot-2022-11-06-at-14-06-29.png) |
| Manage Participant | ![Manage Participant](https://i.ibb.co.com/ynrN7cr/manage-participant.png) |
### Mac OS NOTE

2
src/config/settings.go

@ -5,7 +5,7 @@ import (
)
var (
AppVersion = "v4.15.0"
AppVersion = "v4.16.0"
AppPort = "3000"
AppDebug = false
AppOs = "AldinoKemal"

1
src/domains/app/app.go

@ -7,6 +7,7 @@ import (
type IAppService interface {
Login(ctx context.Context) (response LoginResponse, err error)
LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error)
Logout(ctx context.Context) (err error)
Reconnect(ctx context.Context) (err error)
FirstDevice(ctx context.Context) (response DevicesResponse, err error)

8
src/go.mod

@ -17,8 +17,8 @@ require (
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/valyala/fasthttp v1.55.0
go.mau.fi/libsignal v0.1.1-0.20240705162345-47e713a595ab
go.mau.fi/whatsmeow v0.0.0-20240710112833-d732338c041f
go.mau.fi/libsignal v0.1.1
go.mau.fi/whatsmeow v0.0.0-20240726213518-bb5852f056ca
google.golang.org/protobuf v1.34.2
)
@ -37,7 +37,7 @@ require (
github.com/kr/pretty v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/zerolog v1.33.0 // indirect
@ -45,7 +45,7 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
go.mau.fi/util v0.5.0 // indirect
go.mau.fi/util v0.6.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/net v0.27.0 // indirect

8
src/go.sum

@ -71,6 +71,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -119,10 +121,14 @@ go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c=
go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
go.mau.fi/libsignal v0.1.1-0.20240705162345-47e713a595ab h1:/tnRxsaaG/xBGjXTb6tzTr+XY4T5fQlrGHE1p9ir/wM=
go.mau.fi/libsignal v0.1.1-0.20240705162345-47e713a595ab/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
go.mau.fi/libsignal v0.1.1 h1:m/0PGBh4QKP/I1MQ44ti4C0fMbLMuHb95cmDw01FIpI=
go.mau.fi/libsignal v0.1.1/go.mod h1:QLs89F/OA3ThdSL2Wz2p+o+fi8uuQUz0e1BRa6ExdBw=
go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30=
go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw=
go.mau.fi/util v0.5.0 h1:8yELAl+1CDRrwGe9NUmREgVclSs26Z68pTWePHVxuDo=
go.mau.fi/util v0.5.0/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4=
go.mau.fi/util v0.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg=
go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U=
go.mau.fi/whatsmeow v0.0.0-20240327124018-350073db195c h1:a5O4nqmwUWvmC+27RUdefkuy5XzMOEUqR9ji+/BcHZA=
go.mau.fi/whatsmeow v0.0.0-20240327124018-350073db195c/go.mod h1:kNI5foyzqd77d5HaWc1Jico6/rxtZ/UE8nr80hIsbIk=
go.mau.fi/whatsmeow v0.0.0-20240523075404-7f13c31d2cb1 h1:mUEEmZs1xk5QHKXjDxiAP4bYgyj8r7PaZCafHN+KMQg=
@ -131,6 +137,8 @@ go.mau.fi/whatsmeow v0.0.0-20240619210240-329c2336a6f1 h1:gpFEqwk7WtbF/8HaOMASKE
go.mau.fi/whatsmeow v0.0.0-20240619210240-329c2336a6f1/go.mod h1:0+65CYaE6r4dWzr0dN8i+UZKy0gIfJ79VuSqIl0nKRM=
go.mau.fi/whatsmeow v0.0.0-20240710112833-d732338c041f h1:ni8K5zVngwOWrrZ1HzwEmvAovj0+p0cq464l9g0/dt0=
go.mau.fi/whatsmeow v0.0.0-20240710112833-d732338c041f/go.mod h1:lMW+LxRTakgyNasZwYNB+2uqjKox75GcEfeUXSJhe8I=
go.mau.fi/whatsmeow v0.0.0-20240726213518-bb5852f056ca h1:L0Pc6fi5RevuEASIP6Nd65/HZwCK8wTwm62FEly6UeY=
go.mau.fi/whatsmeow v0.0.0-20240726213518-bb5852f056ca/go.mod h1:BhHKalSq0qNtSCuGIUIvoJyU5KbT4a7k8DQ5yw1Ssk4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=

15
src/internal/rest/app.go

@ -14,6 +14,7 @@ type App struct {
func InitRestApp(app *fiber.App, service domainApp.IAppService) App {
rest := App{Service: service}
app.Get("/app/login", rest.Login)
app.Get("/app/login-with-code", rest.LoginWithCode)
app.Get("/app/logout", rest.Logout)
app.Get("/app/reconnect", rest.Reconnect)
app.Get("/app/devices", rest.Devices)
@ -36,6 +37,20 @@ func (handler *App) Login(c *fiber.Ctx) error {
})
}
func (handler *App) LoginWithCode(c *fiber.Ctx) error {
pairCode, err := handler.Service.LoginWithCode(c.UserContext(), c.Query("phone"))
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Status: 200,
Code: "SUCCESS",
Message: "Login with code success",
Results: map[string]any{
"pair_code": pairCode,
},
})
}
func (handler *App) Logout(c *fiber.Ctx) error {
err := handler.Service.Logout(c.UserContext())
utils.PanicIfNeeded(err)

2
src/pkg/error/app_error.go

@ -101,7 +101,7 @@ func (err sessionSavedError) StatusCode() int {
}
var (
ErrAlreadyLoggedIn = LoginError("you already logged in :)")
ErrAlreadyLoggedIn = LoginError("you are already logged in.")
ErrNotConnected = throwAuthError("you are not connect to services server, please reconnect")
ErrNotLoggedIn = throwAuthError("you are not logged in")
ErrReconnect = throwReconnectError("reconnect error")

23
src/services/app.go

@ -7,6 +7,7 @@ import (
"github.com/aldinokemal/go-whatsapp-web-multidevice/config"
domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
"github.com/aldinokemal/go-whatsapp-web-multidevice/validations"
fiberUtils "github.com/gofiber/fiber/v2/utils"
"github.com/sirupsen/logrus"
"github.com/skip2/go-qrcode"
@ -90,6 +91,28 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp
return response, nil
}
func (service serviceApp) LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error) {
if err = validations.ValidateLoginWithCode(ctx, phoneNumber); err != nil {
logrus.Errorf("Error when validate login with code: %s", err.Error())
return loginCode, err
}
// detect is already logged in
if service.WaCli.IsLoggedIn() {
logrus.Warn("User is already logged in")
return loginCode, pkgError.ErrAlreadyLoggedIn
}
loginCode, err = service.WaCli.PairPhone(phoneNumber, true, whatsmeow.PairClientChrome, "Chrome (Linux)")
if err != nil {
logrus.Errorf("Error when pairing phone: %s", err.Error())
return loginCode, err
}
logrus.Infof("Successfully paired phone with code: %s", loginCode)
return loginCode, nil
}
func (service serviceApp) Logout(_ context.Context) (err error) {
// delete history
files, err := filepath.Glob(fmt.Sprintf("./%s/history-*", config.PathStorages))

21
src/validations/app_validation.go

@ -0,0 +1,21 @@
package validations
import (
"context"
"fmt"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
validation "github.com/go-ozzo/ozzo-validation/v4"
"regexp"
)
func ValidateLoginWithCode(ctx context.Context, phoneNumber string) error {
// Combine validations using a single ValidateWithContext call
err := validation.ValidateWithContext(ctx, &phoneNumber,
validation.Required,
validation.Match(regexp.MustCompile(`^\+?[0-9]{1,15}$`)),
)
if err != nil {
return pkgError.ValidationError(fmt.Sprintf("phone_number(%s): %s", phoneNumber, err.Error()))
}
return nil
}

61
src/validations/app_validation_test.go

@ -0,0 +1,61 @@
package validations
import (
"context"
"testing"
)
func TestValidateLoginWithCode(t *testing.T) {
type args struct {
phoneNumber string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Phone with +",
args: args{phoneNumber: "+6281234567890"},
wantErr: false,
},
{
name: "Phone without +",
args: args{phoneNumber: "621234567890"},
wantErr: false,
},
{
name: "Phone with 0",
args: args{phoneNumber: "081234567890"},
wantErr: false,
},
{
name: "Phone contains alphabet",
args: args{phoneNumber: "+6281234567890a"},
wantErr: true,
},
{
name: "Empty phone number",
args: args{phoneNumber: ""},
wantErr: true,
},
{
name: "Phone with special characters",
args: args{phoneNumber: "+6281234567890!@#"},
wantErr: true,
},
{
name: "Extremely long phone number",
args: args{phoneNumber: "+62812345678901234567890"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := ValidateLoginWithCode(context.Background(), tt.args.phoneNumber); (err != nil) != tt.wantErr {
t.Errorf("ValidateLoginWithCode() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

7
src/views/components/AppLogin.js

@ -1,5 +1,8 @@
export default {
name: 'AppLogin',
props: {
connected: null,
},
data() {
return {
login_link: '',
@ -9,6 +12,8 @@ export default {
methods: {
async openModal() {
try {
if (this.connected) throw Error('You are already logged in.');
await this.submitApi();
$('#modalLogin').modal({
onApprove: function () {
@ -38,7 +43,7 @@ export default {
<div class="content">
<div class="header">Login</div>
<div class="description">
Scan your QRCode and you can use all this API feature
Scan your QR code to access all API capabilities.
</div>
</div>
</div>

109
src/views/components/AppLoginWithCode.js

@ -0,0 +1,109 @@
export default {
name: 'AppLoginWithCode',
props: {
connected: {
type: Boolean,
default: false,
}
},
watch: {
connected: function(val) {
if (val) {
// reset form
this.phone = '';
this.pair_code = null;
$('#modalLoginWithCode').modal('hide');
}
},
},
data: () => {
return {
phone: '',
submitting: false,
pair_code: null,
};
},
methods: {
async openModal() {
try {
if (this.connected) throw Error('You are already logged in.');
$('#modalLoginWithCode').modal({
onApprove: function() {
return false;
},
}).modal('show');
} catch (err) {
showErrorInfo(err);
}
},
async handleSubmit() {
if (this.submitting) return;
try {
this.submitting = true;
const { data } = await http.get(`/app/login-with-code`, {
params: {
phone: this.phone,
},
});
this.pair_code = data.results.pair_code;
} catch (err) {
if (err.response) {
showErrorInfo(err.response.data.message);
}else{
showErrorInfo(err.message);
}
} finally {
this.submitting = false;
}
},
},
template: `
<div class="green card" @click="openModal" style="cursor: pointer">
<div class="content">
<div class="header">Login with Code</div>
<div class="description">
Enter your pairing code to log in and access your devices.
</div>
</div>
</div>
<!-- Modal Login -->
<div class="ui small modal" id="modalLoginWithCode">
<i class="close icon"></i>
<div class="header">
Getting Pair Code
</div>
<div class="content">
<div class="ui message info">
<div class="header">How to pair?</div>
<ol>
<li>Open your Whatsapp</li>
<li>Link a device</li>
<li>Link with pair code</li>
</ol>
</div>
<div class="ui form">
<div class="field">
<label>Phone</label>
<input type="text" v-model="phone" placeholder="Type your phone number"
@keyup.enter="handleSubmit" :disabled="submitting">
<small>Enter to submit</small>
</div>
</div>
<div class="ui grid" v-if="pair_code">
<div class="ui two column centered grid">
<div class="column center aligned">
<div class="header">Pair Code</div>
<p style="font-size: 32px">{{ pair_code }}</p>
</div>
</div>
</div>
</div>
</div>
`,
};

3
src/views/components/AppReconnect.js

@ -28,8 +28,7 @@ export default {
<div class="content">
<div class="header">Reconnect</div>
<div class="description">
Reconnect to whatsapp server, please do this if your api doesn't work or your application is down or
restart
Please reconnect to the WhatsApp service if your API doesn't work or if your app is down.
</div>
</div>
</div>

6
src/views/index.html

@ -41,9 +41,10 @@
</div>
<div class="ui three column stackable grid cards">
<app-login></app-login>
<app-login :connected="connected_devices"></app-login>
<app-logout @reload-devices="handleReloadDevice"></app-logout>
<app-reconnect @reload-devices="handleReloadDevice"></app-reconnect>
<app-login-with-code :connected="connected_devices"></app-login-with-code>
</div>
<div class="ui horizontal divider">
@ -127,6 +128,7 @@
</script>
<script type="module">
import AppLogin from "./components/AppLogin.js";
import AppLoginWithCode from "./components/AppLoginWithCode.js";
import AppLogout from "./components/AppLogout.js";
import AppReconnect from "./components/AppReconnect.js";
import SendMessage from "./components/SendMessage.js";
@ -170,7 +172,7 @@
Vue.createApp({
components: {
AppLogin, AppLogout, AppReconnect,
AppLogin, AppLoginWithCode, AppLogout, AppReconnect,
SendMessage, SendImage, SendFile, SendVideo, SendContact, SendLocation, SendAudio, SendPoll,
MessageDelete, MessageUpdate, MessageReact, MessageRevoke,
GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants,

Loading…
Cancel
Save