Browse Source

feat: add newsletter (#204)

* feat(newsletter): add newsletter service, endpoints, and UI components

Add Newsletter service to support functionality for unfollowing newsletters
Add Newsletter REST controller and routing
Implement newsletter-related endpoints and methods in the User Service
Create UnfollowRequest for the INewsletterService interface
Add MyListNewsletterResponse to user's data fields
Add newsletter validation
Refactor JS components to support newsletter type and simplify recipient forms by moving logic to FormRecipient component
Refactor window global constants to support newsletters
Modify server to initialize and use the newsletter services
Add UI component for listing newsletters
Refactor existing components to use FormRecipient for recipient data input

* chore: update documentation

feat(openapi.yaml): add newsletter support with new paths and schemas
docs(readme.md): update API endpoints including newsletter and images
fix(openapi.yaml): correct duplicated summary text for user my newsletters

* feat: update package name

* feat: Update src/views/components/NewsletterList.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* feat: Update src/views/components/NewsletterList.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* feat: Update src/views/components/NewsletterList.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
pull/208/head v4.20.0
Aldino Kemal 1 year ago
committed by GitHub
parent
commit
c419406a9a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 301
      docs/openapi.yaml
  2. 7
      readme.md
  3. 2
      src/cmd/root.go
  4. 11
      src/domains/newsletter/newsletter.go
  5. 4
      src/domains/user/account.go
  6. 1
      src/domains/user/user.go
  7. 32
      src/internal/rest/newsletter.go
  8. 13
      src/internal/rest/user.go
  9. 8
      src/pkg/whatsapp/whatsapp.go
  10. 32
      src/services/newsletter.go
  11. 14
      src/services/user.go
  12. 20
      src/validations/newsletter_validation.go
  13. 25
      src/views/components/AccountAvatar.js
  14. 24
      src/views/components/AccountUserInfo.js
  15. 26
      src/views/components/MessageDelete.js
  16. 26
      src/views/components/MessageReact.js
  17. 26
      src/views/components/MessageRevoke.js
  18. 26
      src/views/components/MessageUpdate.js
  19. 117
      src/views/components/NewsletterList.js
  20. 25
      src/views/components/SendAudio.js
  21. 26
      src/views/components/SendContact.js
  22. 26
      src/views/components/SendFile.js
  23. 26
      src/views/components/SendImage.js
  24. 26
      src/views/components/SendLocation.js
  25. 25
      src/views/components/SendMessage.js
  26. 26
      src/views/components/SendPoll.js
  27. 26
      src/views/components/SendVideo.js
  28. 52
      src/views/components/generic/FormRecipient.js
  29. 17
      src/views/index.html

301
docs/openapi.yaml

@ -1,7 +1,7 @@
openapi: 3.0.0 openapi: 3.0.0
info: info:
title: WhatsApp API MultiDevice title: WhatsApp API MultiDevice
version: 4.2.0
version: 4.3.0
description: This API is used for sending whatsapp via API description: This API is used for sending whatsapp via API
servers: servers:
- url: http://localhost:3000 - url: http://localhost:3000
@ -16,6 +16,8 @@ tags:
description: Message manipulation (revoke/react/update). description: Message manipulation (revoke/react/update).
- name: group - name: group
description: Group setting description: Group setting
- name: newsletter
description: newsletter setting
paths: paths:
/app/login: /app/login:
get: get:
@ -212,6 +214,31 @@ paths:
- user - user
summary: User My List Groups summary: User My List Groups
responses: responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/UserGroupResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorInternalServer'
/user/my/newsletters:
get:
operationId: userMyNewsletter
tags:
- user
summary: User My List Groups
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/NewsletterResponse'
'500': '500':
description: Internal Server Error description: Internal Server Error
content: content:
@ -1042,6 +1069,40 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/ErrorInternalServer' $ref: '#/components/schemas/ErrorInternalServer'
/newsletter/unfollow:
post:
operationId: unfollowNewsletter
tags:
- newsletter
summary: Unfollow newsletter
requestBody:
content:
application/json:
schema:
type: object
properties:
newsletter_id:
type: string
example: '120363024512399999@newsletter'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/GenericResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorBadRequest'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorInternalServer'
components: components:
schemas: schemas:
@ -1342,3 +1403,241 @@ components:
type: object type: object
example: null example: null
description: 'additional data' description: 'additional data'
NewsletterResponse:
type: object
properties:
code:
type: string
example: "SUCCESS"
message:
type: string
example: "Success get list newsletter"
results:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Newsletter'
Newsletter:
type: object
properties:
id:
type: string
example: "120363144038483540@newsletter"
state:
type: object
properties:
type:
type: string
example: "active"
thread_metadata:
type: object
properties:
creation_time:
type: string
example: "1688746895"
invite:
type: string
example: "0029Va4K0PZ5a245NkngBA2M"
name:
type: object
properties:
text:
type: string
example: "WhatsApp"
id:
type: string
example: "1688746895480511"
update_time:
type: string
example: "1688746895480511"
description:
type: object
properties:
text:
type: string
example: "WhatsApp’s official channel. Follow for our latest feature launches, updates, exclusive drops and more."
id:
type: string
example: "1689653839450668"
update_time:
type: string
example: "1689653839450668"
subscribers_count:
type: string
example: "0"
verification:
type: string
example: "verified"
picture:
type: object
properties:
url:
type: string
example: ""
id:
type: string
example: "1707950960975554"
type:
type: string
example: "IMAGE"
direct_path:
type: string
example: "/v/t61.24694-24/416962407_970228831134395_8869146381947923973_n.jpg?ccb=11-4&oh=01_Q5AaIIvOIeu3l0HCZWILrmr-dGR_vXFqnhUeytw0-ojPc4hL&oe=670D95B1&_nc_sid=5e03e0&_nc_cat=110"
preview:
type: object
properties:
url:
type: string
example: ""
id:
type: string
example: "1707950960975554"
type:
type: string
example: "PREVIEW"
direct_path:
type: string
example: "/v/t61.24694-24/416962407_970228831134395_8869146381947923973_n.jpg?stp=dst-jpg_s192x192&ccb=11-4&oh=01_Q5AaIHO-DQklqm3q3awF7xwji_WAn9DkgZASQA0B2Ct0qbSa&oe=670D95B1&_nc_sid=5e03e0&_nc_cat=110"
settings:
type: object
properties:
reaction_codes:
type: object
properties:
value:
type: string
example: "ALL"
viewer_metadata:
type: object
properties:
mute:
type: string
example: "off"
role:
type: string
example: "subscriber"
GroupResponse:
type: object
properties:
code:
type: string
example: "SUCCESS"
message:
type: string
example: "Success get list groups"
results:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Group'
Group:
type: object
properties:
JID:
type: string
example: "120363347168689807@g.us"
OwnerJID:
type: string
example: "6288228744537@s.whatsapp.net"
Name:
type: string
example: "Example Group"
NameSetAt:
type: string
format: date-time
example: "2024-10-11T21:27:29+07:00"
NameSetBy:
type: string
example: "6288228744537@s.whatsapp.net"
Topic:
type: string
example: ""
TopicID:
type: string
example: ""
TopicSetAt:
type: string
format: date-time
example: "0001-01-01T00:00:00Z"
TopicSetBy:
type: string
example: ""
TopicDeleted:
type: boolean
example: false
IsLocked:
type: boolean
example: false
IsAnnounce:
type: boolean
example: false
AnnounceVersionID:
type: string
example: "1728656849439709"
IsEphemeral:
type: boolean
example: false
DisappearingTimer:
type: integer
example: 0
IsIncognito:
type: boolean
example: false
IsParent:
type: boolean
example: false
DefaultMembershipApprovalMode:
type: string
example: ""
LinkedParentJID:
type: string
example: ""
IsDefaultSubGroup:
type: boolean
example: false
IsJoinApprovalRequired:
type: boolean
example: false
GroupCreated:
type: string
format: date-time
example: "2024-10-11T21:27:29+07:00"
ParticipantVersionID:
type: string
example: "1728656849439790"
Participants:
type: array
items:
$ref: '#/components/schemas/Participant'
MemberAddMode:
type: string
example: "admin_add"
Participant:
type: object
properties:
JID:
type: string
example: "6288228744537@s.whatsapp.net"
LID:
type: string
example: "20036609675500@lid"
IsAdmin:
type: boolean
example: true
IsSuperAdmin:
type: boolean
example: true
DisplayName:
type: string
example: ""
Error:
type: integer
example: 0
AddRequest:
type: string
example: null

7
readme.md

@ -112,7 +112,8 @@ You can fork or edit this source code !
| ✅ | Devices | GET | /app/devices | | ✅ | Devices | GET | /app/devices |
| ✅ | User Info | GET | /user/info | | ✅ | User Info | GET | /user/info |
| ✅ | User Avatar | GET | /user/avatar | | ✅ | User Avatar | GET | /user/avatar |
| ✅ | User My Group List | GET | /user/my/groups |
| ✅ | User My Groups | GET | /user/my/groups |
| ✅ | User My Newsletter | GET | /user/my/newsletters |
| ✅ | User My Privacy Setting | GET | /user/my/privacy | | ✅ | User My Privacy Setting | GET | /user/my/privacy |
| ✅ | Send Message | POST | /send/message | | ✅ | Send Message | POST | /send/message |
| ✅ | Send Image | POST | /send/image | | ✅ | Send Image | POST | /send/image |
@ -135,6 +136,7 @@ You can fork or edit this source code !
| ✅ | Remove Participant in Group | POST | /group/participants/remove | | ✅ | Remove Participant in Group | POST | /group/participants/remove |
| ✅ | Promote Participant in Group | POST | /group/participants/promote | | ✅ | Promote Participant in Group | POST | /group/participants/promote |
| ✅ | Demote Participant in Group | POST | /group/participants/demote | | ✅ | Demote Participant in Group | POST | /group/participants/demote |
| ✅ | Unfollow Newsletter | POST | /group/newsletter/unfollow |
``` ```
✅ = Available ✅ = Available
@ -145,7 +147,7 @@ You can fork or edit this source code !
| Description | Image | | Description | Image |
|--------------------|------------------------------------------------------------------------------------------| |--------------------|------------------------------------------------------------------------------------------|
| Homepage | ![Homepage](https://i.ibb.co.com/L0B1LVb/homepage-v4-16.png) |
| Homepage | ![Homepage](https://i.ibb.co.com/Sy0dHZp/homepage-v4-20.png) |
| Login | ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1) | | 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) | | 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 Message | ![Send Message](https://i.ibb.co.com/rc3NXMX/send-message.png?v1) |
@ -167,6 +169,7 @@ You can fork or edit this source code !
| Auto Reply | ![Auto Reply](https://i.ibb.co.com/D4rTytX/IMG-20220517-162500.jpg) | | 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) | | 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) | | Manage Participant | ![Manage Participant](https://i.ibb.co.com/ynrN7cr/manage-participant.png) |
| My Newsletter | ![List Newsletter](https://i.ibb.co.com/WDg50jJ/image.png) |
### Mac OS NOTE ### Mac OS NOTE

2
src/cmd/root.go

@ -113,6 +113,7 @@ func runRest(_ *cobra.Command, _ []string) {
userService := services.NewUserService(cli) userService := services.NewUserService(cli)
messageService := services.NewMessageService(cli) messageService := services.NewMessageService(cli)
groupService := services.NewGroupService(cli) groupService := services.NewGroupService(cli)
newsletterService := services.NewNewsletterService(cli)
// Rest // Rest
rest.InitRestApp(app, appService) rest.InitRestApp(app, appService)
@ -120,6 +121,7 @@ func runRest(_ *cobra.Command, _ []string) {
rest.InitRestUser(app, userService) rest.InitRestUser(app, userService)
rest.InitRestMessage(app, messageService) rest.InitRestMessage(app, messageService)
rest.InitRestGroup(app, groupService) rest.InitRestGroup(app, groupService)
rest.InitRestNewsletter(app, newsletterService)
app.Get("/", func(c *fiber.Ctx) error { app.Get("/", func(c *fiber.Ctx) error {
return c.Render("views/index", fiber.Map{ return c.Render("views/index", fiber.Map{

11
src/domains/newsletter/newsletter.go

@ -0,0 +1,11 @@
package newsletter
import "context"
type INewsletterService interface {
Unfollow(ctx context.Context, request UnfollowRequest) (err error)
}
type UnfollowRequest struct {
NewsletterID string `json:"newsletter_id" form:"newsletter_id"`
}

4
src/domains/user/account.go

@ -48,3 +48,7 @@ type MyPrivacySettingResponse struct {
type MyListGroupsResponse struct { type MyListGroupsResponse struct {
Data []types.GroupInfo `json:"data"` Data []types.GroupInfo `json:"data"`
} }
type MyListNewsletterResponse struct {
Data []types.NewsletterMetadata `json:"data"`
}

1
src/domains/user/user.go

@ -8,5 +8,6 @@ type IUserService interface {
Info(ctx context.Context, request InfoRequest) (response InfoResponse, err error) Info(ctx context.Context, request InfoRequest) (response InfoResponse, err error)
Avatar(ctx context.Context, request AvatarRequest) (response AvatarResponse, err error) Avatar(ctx context.Context, request AvatarRequest) (response AvatarResponse, err error)
MyListGroups(ctx context.Context) (response MyListGroupsResponse, err error) MyListGroups(ctx context.Context) (response MyListGroupsResponse, err error)
MyListNewsletter(ctx context.Context) (response MyListNewsletterResponse, err error)
MyPrivacySetting(ctx context.Context) (response MyPrivacySettingResponse, err error) MyPrivacySetting(ctx context.Context) (response MyPrivacySettingResponse, err error)
} }

32
src/internal/rest/newsletter.go

@ -0,0 +1,32 @@
package rest
import (
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/gofiber/fiber/v2"
)
type Newsletter struct {
Service domainNewsletter.INewsletterService
}
func InitRestNewsletter(app *fiber.App, service domainNewsletter.INewsletterService) Newsletter {
rest := Newsletter{Service: service}
app.Post("/newsletter/unfollow", rest.Unfollow)
return rest
}
func (controller *Newsletter) Unfollow(c *fiber.Ctx) error {
var request domainNewsletter.UnfollowRequest
err := c.BodyParser(&request)
utils.PanicIfNeeded(err)
err = controller.Service.Unfollow(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Status: 200,
Code: "SUCCESS",
Message: "Success unfollow newsletter",
})
}

13
src/internal/rest/user.go

@ -17,6 +17,7 @@ func InitRestUser(app *fiber.App, service domainUser.IUserService) User {
app.Get("/user/avatar", rest.UserAvatar) app.Get("/user/avatar", rest.UserAvatar)
app.Get("/user/my/privacy", rest.UserMyPrivacySetting) app.Get("/user/my/privacy", rest.UserMyPrivacySetting)
app.Get("/user/my/groups", rest.UserMyListGroups) app.Get("/user/my/groups", rest.UserMyListGroups)
app.Get("/user/my/newsletters", rest.UserMyListNewsletter)
return rest return rest
} }
@ -80,3 +81,15 @@ func (controller *User) UserMyListGroups(c *fiber.Ctx) error {
Results: response, Results: response,
}) })
} }
func (controller *User) UserMyListNewsletter(c *fiber.Ctx) error {
response, err := controller.Service.MyListNewsletter(c.UserContext())
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Status: 200,
Code: "SUCCESS",
Message: "Success get list newsletter",
Results: response,
})
}

8
src/pkg/whatsapp/whatsapp.go

@ -107,17 +107,19 @@ func ParseJID(arg string) (types.JID, error) {
} }
if !strings.ContainsRune(arg, '@') { if !strings.ContainsRune(arg, '@') {
return types.NewJID(arg, types.DefaultUserServer), nil return types.NewJID(arg, types.DefaultUserServer), nil
} else {
}
recipient, err := types.ParseJID(arg) recipient, err := types.ParseJID(arg)
if err != nil { if err != nil {
fmt.Printf("invalid JID %s: %v", arg, err) fmt.Printf("invalid JID %s: %v", arg, err)
return recipient, pkgError.ErrInvalidJID return recipient, pkgError.ErrInvalidJID
} else if recipient.User == "" {
}
if recipient.User == "" {
fmt.Printf("invalid JID %v: no server specified", arg) fmt.Printf("invalid JID %v: no server specified", arg)
return recipient, pkgError.ErrInvalidJID return recipient, pkgError.ErrInvalidJID
} }
return recipient, nil return recipient, nil
}
} }
func IsOnWhatsapp(waCli *whatsmeow.Client, jid string) bool { func IsOnWhatsapp(waCli *whatsmeow.Client, jid string) bool {

32
src/services/newsletter.go

@ -0,0 +1,32 @@
package services
import (
"context"
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"github.com/aldinokemal/go-whatsapp-web-multidevice/validations"
"go.mau.fi/whatsmeow"
)
type newsletterService struct {
WaCli *whatsmeow.Client
}
func NewNewsletterService(waCli *whatsmeow.Client) domainNewsletter.INewsletterService {
return &newsletterService{
WaCli: waCli,
}
}
func (service newsletterService) Unfollow(ctx context.Context, request domainNewsletter.UnfollowRequest) (err error) {
if err = validations.ValidateUnfollowNewsletter(ctx, request); err != nil {
return err
}
JID, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.NewsletterID)
if err != nil {
return err
}
return service.WaCli.UnfollowNewsletter(JID)
}

14
src/services/user.go

@ -127,6 +127,20 @@ func (service userService) MyListGroups(_ context.Context) (response domainUser.
return response, nil return response, nil
} }
func (service userService) MyListNewsletter(_ context.Context) (response domainUser.MyListNewsletterResponse, err error) {
whatsapp.MustLogin(service.WaCli)
datas, err := service.WaCli.GetSubscribedNewsletters()
if err != nil {
return
}
fmt.Printf("%+v\n", datas)
for _, data := range datas {
response.Data = append(response.Data, *data)
}
return response, nil
}
func (service userService) MyPrivacySetting(_ context.Context) (response domainUser.MyPrivacySettingResponse, err error) { func (service userService) MyPrivacySetting(_ context.Context) (response domainUser.MyPrivacySettingResponse, err error) {
whatsapp.MustLogin(service.WaCli) whatsapp.MustLogin(service.WaCli)

20
src/validations/newsletter_validation.go

@ -0,0 +1,20 @@
package validations
import (
"context"
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newsletter"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
validation "github.com/go-ozzo/ozzo-validation/v4"
)
func ValidateUnfollowNewsletter(ctx context.Context, request domainNewsletter.UnfollowRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.NewsletterID, validation.Required),
)
if err != nil {
return pkgError.ValidationError(err.Error())
}
return nil
}

25
src/views/components/AccountAvatar.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'AccountAvatar', name: 'AccountAvatar',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
image: null, image: null,
loading: false, loading: false,
@ -12,7 +17,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -45,7 +50,7 @@ export default {
handleReset() { handleReset() {
this.phone = ''; this.phone = '';
this.image = null; this.image = null;
this.type = 'user';
this.type = window.TYPEUSER;
} }
}, },
template: ` template: `
@ -66,19 +71,7 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Preview</label> <label>Preview</label>

24
src/views/components/AccountUserInfo.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'AccountUserInfo', name: 'AccountUserInfo',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
// //
name: null, name: null,
@ -15,7 +20,7 @@ export default {
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -52,7 +57,7 @@ export default {
this.name = null; this.name = null;
this.status = null; this.status = null;
this.devices = []; this.devices = [];
this.type = 'user';
this.type = window.TYPEUSER;
} }
}, },
template: ` template: `
@ -74,18 +79,7 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<button type="button" class="ui primary button" :class="{'loading': loading}" <button type="button" class="ui primary button" :class="{'loading': loading}"
@click="handleSubmit"> @click="handleSubmit">

26
src/views/components/MessageDelete.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'DeleteMessage', name: 'DeleteMessage',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
message_id: '', message_id: '',
loading: false, loading: false,
@ -10,7 +15,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -48,7 +53,7 @@ export default {
} }
}, },
handleReset() { handleReset() {
this.type = 'user';
this.type = window.TYPEUSER;
this.phone = ''; this.phone = '';
this.message_id = ''; this.message_id = '';
this.new_message = ''; this.new_message = '';
@ -74,19 +79,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Message ID</label> <label>Message ID</label>
<input v-model="message_id" type="text" placeholder="Please enter your message id" <input v-model="message_id" type="text" placeholder="Please enter your message id"

26
src/views/components/MessageReact.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'ReactMessage', name: 'ReactMessage',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
message_id: '', message_id: '',
emoji: '', emoji: '',
@ -11,7 +16,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -51,7 +56,7 @@ export default {
this.phone = ''; this.phone = '';
this.message_id = ''; this.message_id = '';
this.emoji = ''; this.emoji = '';
this.type = 'user';
this.type = window.TYPEUSER;
}, },
}, },
template: ` template: `
@ -74,19 +79,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Message ID</label> <label>Message ID</label>
<input v-model="message_id" type="text" placeholder="Please enter your message id" <input v-model="message_id" type="text" placeholder="Please enter your message id"

26
src/views/components/MessageRevoke.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'Message', name: 'Message',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
message_id: '', message_id: '',
loading: false, loading: false,
@ -10,7 +15,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -49,7 +54,7 @@ export default {
handleReset() { handleReset() {
this.phone = ''; this.phone = '';
this.message_id = ''; this.message_id = '';
this.type = 'user';
this.type = window.TYPEUSER;
}, },
}, },
template: ` template: `
@ -71,19 +76,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label> Message ID</label> <label> Message ID</label>
<input v-model="message_id" type="text" placeholder="Please enter your message id" <input v-model="message_id" type="text" placeholder="Please enter your message id"

26
src/views/components/MessageUpdate.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'UpdateMessage', name: 'UpdateMessage',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
message_id: '', message_id: '',
new_message: '', new_message: '',
@ -11,7 +16,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -49,7 +54,7 @@ export default {
} }
}, },
handleReset() { handleReset() {
this.type = 'user';
this.type = window.TYPEUSER;
this.phone = ''; this.phone = '';
this.message_id = ''; this.message_id = '';
this.new_message = ''; this.new_message = '';
@ -75,19 +80,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Message ID</label> <label>Message ID</label>
<input v-model="message_id" type="text" placeholder="Please enter your message id" <input v-model="message_id" type="text" placeholder="Please enter your message id"

117
src/views/components/NewsletterList.js

@ -0,0 +1,117 @@
export default {
name: 'ListNewsletter',
data() {
return {
newsletters: []
}
},
methods: {
async openModal() {
try {
this.dtClear()
await this.submitApi();
$('#modalNewsletterList').modal('show');
this.dtRebuild()
showSuccessInfo("Newsletters fetched")
} catch (err) {
showErrorInfo(err)
}
},
dtClear() {
$('#account_newsletters_table').DataTable().destroy();
},
dtRebuild() {
$('#account_newsletters_table').DataTable({
"pageLength": 100,
"reloadData": true,
}).draw();
},
async handleUnfollowNewsletter(newsletter_id) {
try {
const ok = confirm("Are you sure to leave this newsletter?");
if (!ok) return;
await this.unfollowNewsletterApi(newsletter_id);
this.dtClear()
await this.submitApi();
this.dtRebuild()
showSuccessInfo("Success unfollow newsletter")
} catch (err) {
showErrorInfo(err)
}
},
async unfollowNewsletterApi(newsletter_id) {
try {
let payload = {
newsletter_id: newsletter_id
};
await window.http.post(`/newsletter/unfollow`, payload)
} catch (error) {
if (error.response) {
throw new Error(error.response.data.message);
}
throw new Error(error.message);
}
},
async submitApi() {
try {
let response = await window.http.get(`/user/my/newsletters`)
this.newsletters = response.data.results.data;
} catch (error) {
if (error.response) {
throw new Error(error.response.data.message);
}
throw new Error(error.message);
}
},
formatDate: function (value) {
if (!value) return ''
if (isNaN(value)) return 'Invalid date';
return moment.unix(value).format('LLL');
}
},
template: `
<div class="green card" @click="openModal" style="cursor: pointer">
<div class="content">
<a class="ui green right ribbon label">Newsletter</a>
<div class="header">List Newsletters</div>
<div class="description">
Display all your newsletters
</div>
</div>
</div>
<!-- Modal AccountNewsletter -->
<div class="ui small modal" id="modalNewsletterList">
<i class="close icon"></i>
<div class="header">
My Newsletter List
</div>
<div class="content">
<table class="ui celled table" id="account_newsletters_table">
<thead>
<tr>
<th>Newsletter ID</th>
<th>Name</th>
<th>Role</th>
<th>Created At</th>
<th>Action</th>
</tr>
</thead>
<tbody v-if="newsletters != null">
<tr v-for="n in newsletters">
<td>{{ n.id.split('@')[0] }}</td>
<td>{{ n.thread_metadata?.name?.text || 'N/A' }}</td>
<td>{{ n.viewer_metadata?.role || 'N/A' }}</td>
<td>{{ formatDate(n.thread_metadata?.creation_time) }}</td>
<td>
<button class="ui red tiny button" @click="handleUnfollowNewsletter(n.id)">Unfollow</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
`
}

25
src/views/components/SendAudio.js

@ -1,15 +1,20 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'Send', name: 'Send',
components: {
FormRecipient
},
data() { data() {
return { return {
phone: '', phone: '',
type: 'user',
type: window.TYPEUSER,
loading: false, loading: false,
} }
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -49,7 +54,7 @@ export default {
}, },
handleReset() { handleReset() {
this.phone = ''; this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_audio").val(''); $("#file_audio").val('');
}, },
}, },
@ -72,19 +77,7 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field" style="padding-bottom: 30px"> <div class="field" style="padding-bottom: 30px">
<label>Audio</label> <label>Audio</label>
<input type="file" style="display: none" accept="audio/*" id="file_audio"/> <input type="file" style="display: none" accept="audio/*" id="file_audio"/>

26
src/views/components/SendContact.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendContact', name: 'SendContact',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
card_name: '', card_name: '',
card_phone: '', card_phone: '',
@ -11,7 +16,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -58,7 +63,7 @@ export default {
this.phone = ''; this.phone = '';
this.card_name = ''; this.card_name = '';
this.card_phone = ''; this.card_phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
}, },
}, },
template: ` template: `
@ -80,19 +85,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Contact Name</label> <label>Contact Name</label>
<input v-model="card_name" type="text" placeholder="Please enter contact name" <input v-model="card_name" type="text" placeholder="Please enter contact name"

26
src/views/components/SendFile.js

@ -1,5 +1,10 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendFile', name: 'SendFile',
components: {
FormRecipient
},
props: { props: {
maxFileSize: { maxFileSize: {
type: String, type: String,
@ -9,14 +14,14 @@ export default {
data() { data() {
return { return {
caption: '', caption: '',
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
loading: false, loading: false,
} }
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -58,7 +63,7 @@ export default {
handleReset() { handleReset() {
this.caption = ''; this.caption = '';
this.phone = ''; this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_file").val(''); $("#file_file").val('');
}, },
}, },
@ -82,19 +87,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Caption</label> <label>Caption</label>
<textarea v-model="caption" placeholder="Type some caption (optional)..." <textarea v-model="caption" placeholder="Type some caption (optional)..."

26
src/views/components/SendImage.js

@ -1,19 +1,24 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendImage', name: 'SendImage',
components: {
FormRecipient
},
data() { data() {
return { return {
phone: '', phone: '',
view_once: false, view_once: false,
compress: false, compress: false,
caption: '', caption: '',
type: 'user',
type: window.TYPEUSER,
loading: false, loading: false,
selected_file: null selected_file: null
} }
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -60,7 +65,7 @@ export default {
this.compress = false; this.compress = false;
this.phone = ''; this.phone = '';
this.caption = ''; this.caption = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_image").val(''); $("#file_image").val('');
}, },
}, },
@ -85,19 +90,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Caption</label> <label>Caption</label>
<textarea v-model="caption" type="text" placeholder="Hello this is image caption" <textarea v-model="caption" type="text" placeholder="Hello this is image caption"

26
src/views/components/SendLocation.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendLocation', name: 'SendLocation',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
latitude: '', latitude: '',
longitude: '', longitude: '',
@ -11,7 +16,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -56,7 +61,7 @@ export default {
this.phone = ''; this.phone = '';
this.latitude = ''; this.latitude = '';
this.longitude = ''; this.longitude = '';
this.type = 'user';
this.type = window.TYPEUSER;
}, },
}, },
template: ` template: `
@ -78,19 +83,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Location Latitude</label> <label>Location Latitude</label>
<input v-model="latitude" type="text" placeholder="Please enter latitude" <input v-model="latitude" type="text" placeholder="Please enter latitude"

25
src/views/components/SendMessage.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendMessage', name: 'SendMessage',
components: {
FormRecipient
},
data() { data() {
return { return {
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
text: '', text: '',
reply_message_id: '', reply_message_id: '',
@ -11,7 +16,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -57,7 +62,7 @@ export default {
handleReset() { handleReset() {
this.phone = ''; this.phone = '';
this.text = ''; this.text = '';
this.type = 'user';
this.type = window.TYPEUSER;
this.reply_message_id = ''; this.reply_message_id = '';
}, },
}, },
@ -80,19 +85,7 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Reply Message ID</label> <label>Reply Message ID</label>
<input v-model="reply_message_id" type="text" <input v-model="reply_message_id" type="text"

26
src/views/components/SendPoll.js

@ -1,10 +1,15 @@
// export Vue Component // export Vue Component
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendPoll', name: 'SendPoll',
components: {
FormRecipient
},
data() { data() {
return { return {
phone: '', phone: '',
type: 'user',
type: window.TYPEUSER,
loading: false, loading: false,
question: '', question: '',
options: ['', ''], options: ['', ''],
@ -13,7 +18,7 @@ export default {
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -56,7 +61,7 @@ export default {
}, },
handleReset() { handleReset() {
this.phone = ''; this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
this.question = ''; this.question = '';
this.options = ['', '']; this.options = ['', ''];
this.max_vote = 1; this.max_vote = 1;
@ -87,19 +92,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Question</label> <label>Question</label>
<input v-model="question" type="text" placeholder="Please enter question" <input v-model="question" type="text" placeholder="Please enter question"

26
src/views/components/SendVideo.js

@ -1,5 +1,10 @@
import FormRecipient from "./generic/FormRecipient.js";
export default { export default {
name: 'SendVideo', name: 'SendVideo',
components: {
FormRecipient
},
// define props // define props
props: { props: {
maxVideoSize: { maxVideoSize: {
@ -12,14 +17,14 @@ export default {
caption: '', caption: '',
view_once: false, view_once: false,
compress: false, compress: false,
type: 'user',
type: window.TYPEUSER,
phone: '', phone: '',
loading: false, loading: false,
} }
}, },
computed: { computed: {
phone_id() { phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
} }
}, },
methods: { methods: {
@ -65,7 +70,7 @@ export default {
this.view_once = false; this.view_once = false;
this.compress = false; this.compress = false;
this.phone = ''; this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_video").val(''); $("#file_video").val('');
}, },
}, },
@ -91,19 +96,8 @@ export default {
</div> </div>
<div class="content"> <div class="content">
<form class="ui form"> <form class="ui form">
<div class="field">
<label>Type</label>
<select name="type" v-model="type" aria-label="type">
<option value="group">Group Message</option>
<option value="user">Private Message</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input v-model="phone" type="text" placeholder="6289..."
aria-label="phone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
<FormRecipient v-model:type="type" v-model:phone="phone"/>
<div class="field"> <div class="field">
<label>Caption</label> <label>Caption</label>
<textarea v-model="caption" placeholder="Type some caption (optional)..." <textarea v-model="caption" placeholder="Type some caption (optional)..."

52
src/views/components/generic/FormRecipient.js

@ -0,0 +1,52 @@
export default {
name: 'FormRecipient',
props: {
type: {
type: String,
required: true
},
phone: {
type: String,
required: true
},
},
data() {
return {
recipientTypes: []
};
},
computed: {
phone_id() {
return this.phone + this.type;
}
},
mounted() {
this.recipientTypes = [
{ value: window.TYPEUSER, text: 'Private Message' },
{ value: window.TYPEGROUP, text: 'Group Message' },
{ value: window.TYPENEWSLETTER, text: 'Newsletter' }
];
},
methods: {
updateType(event) {
this.$emit('update:type', event.target.value);
},
updatePhone(event) {
this.$emit('update:phone', event.target.value);
}
},
template: `
<div class="field">
<label>Type</label>
<select name="type" @change="updateType" class="ui dropdown">
<option v-for="type in recipientTypes" :value="type.value">{{ type.text }}</option>
</select>
</div>
<div class="field">
<label>Phone / Group ID</label>
<input :value="phone" aria-label="wa identifier" @input="updatePhone">
<input :value="phone_id" disabled aria-label="whatsapp_id">
</div>
`
}

17
src/views/index.html

@ -86,6 +86,14 @@
<group-add-participants></group-add-participants> <group-add-participants></group-add-participants>
</div> </div>
<div class="ui horizontal divider">
Newsletter
</div>
<div class="ui three column doubling grid cards">
<newsletter-list></newsletter-list>
</div>
<div class="ui horizontal divider"> <div class="ui horizontal divider">
Account Account
</div> </div>
@ -98,8 +106,9 @@
</div> </div>
<script> <script>
window.TYPEGROUP = "g.us";
window.TYPEUSER = "s.whatsapp.net";
window.TYPEGROUP = "@g.us";
window.TYPEUSER = "@s.whatsapp.net";
window.TYPENEWSLETTER = "@newsletter";
window.showErrorInfo = (message) => { window.showErrorInfo = (message) => {
$('body').toast({ $('body').toast({
position: 'bottom right', position: 'bottom right',
@ -120,7 +129,7 @@
} }
window.http = axios.create({ window.http = axios.create({
baseURL: `${window.location.protocol}//${window.location.hostname}`
baseURL: `${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}`
}); });
{{ if isEnableBasicAuth .BasicAuthToken }} {{ if isEnableBasicAuth .BasicAuthToken }}
window.http.defaults.headers.common['Authorization'] = {{ .BasicAuthToken }}; window.http.defaults.headers.common['Authorization'] = {{ .BasicAuthToken }};
@ -150,6 +159,7 @@
import AccountAvatar from "./components/AccountAvatar.js"; import AccountAvatar from "./components/AccountAvatar.js";
import AccountUserInfo from "./components/AccountUserInfo.js"; import AccountUserInfo from "./components/AccountUserInfo.js";
import AccountPrivacy from "./components/AccountPrivacy.js"; import AccountPrivacy from "./components/AccountPrivacy.js";
import NewsletterList from "./components/NewsletterList.js";
const showErrorInfo = (message) => { const showErrorInfo = (message) => {
$('body').toast({ $('body').toast({
@ -176,6 +186,7 @@
SendMessage, SendImage, SendFile, SendVideo, SendContact, SendLocation, SendAudio, SendPoll, SendMessage, SendImage, SendFile, SendVideo, SendContact, SendLocation, SendAudio, SendPoll,
MessageDelete, MessageUpdate, MessageReact, MessageRevoke, MessageDelete, MessageUpdate, MessageReact, MessageRevoke,
GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants, GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants,
NewsletterList,
AccountAvatar, AccountUserInfo, AccountPrivacy AccountAvatar, AccountUserInfo, AccountPrivacy
}, },
delimiters: ['[[', ']]'], delimiters: ['[[', ']]'],

Loading…
Cancel
Save