Browse Source

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
pull/204/head
Aldino Kemal 1 year ago
parent
commit
dd4ab8f010
  1. 2
      src/cmd/root.go
  2. 11
      src/domains/newletter/newsletter.go
  3. 4
      src/domains/user/account.go
  4. 1
      src/domains/user/user.go
  5. 32
      src/internal/rest/newsletter.go
  6. 13
      src/internal/rest/user.go
  7. 22
      src/pkg/whatsapp/whatsapp.go
  8. 32
      src/services/newsletter.go
  9. 14
      src/services/user.go
  10. 20
      src/validations/newsletter_validation.go
  11. 25
      src/views/components/AccountAvatar.js
  12. 24
      src/views/components/AccountUserInfo.js
  13. 26
      src/views/components/MessageDelete.js
  14. 26
      src/views/components/MessageReact.js
  15. 26
      src/views/components/MessageRevoke.js
  16. 26
      src/views/components/MessageUpdate.js
  17. 115
      src/views/components/NewsletterList.js
  18. 25
      src/views/components/SendAudio.js
  19. 26
      src/views/components/SendContact.js
  20. 26
      src/views/components/SendFile.js
  21. 26
      src/views/components/SendImage.js
  22. 26
      src/views/components/SendLocation.js
  23. 25
      src/views/components/SendMessage.js
  24. 26
      src/views/components/SendPoll.js
  25. 26
      src/views/components/SendVideo.js
  26. 52
      src/views/components/generic/FormRecipient.js
  27. 17
      src/views/index.html

2
src/cmd/root.go

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

11
src/domains/newletter/newsletter.go

@ -0,0 +1,11 @@
package newletter
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 {
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)
Avatar(ctx context.Context, request AvatarRequest) (response AvatarResponse, 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)
}

32
src/internal/rest/newsletter.go

@ -0,0 +1,32 @@
package rest
import (
domainNewsletter "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/newletter"
"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/my/privacy", rest.UserMyPrivacySetting)
app.Get("/user/my/groups", rest.UserMyListGroups)
app.Get("/user/my/newsletters", rest.UserMyListNewsletter)
return rest
}
@ -80,3 +81,15 @@ func (controller *User) UserMyListGroups(c *fiber.Ctx) error {
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,
})
}

22
src/pkg/whatsapp/whatsapp.go

@ -107,17 +107,19 @@ func ParseJID(arg string) (types.JID, error) {
}
if !strings.ContainsRune(arg, '@') {
return types.NewJID(arg, types.DefaultUserServer), nil
} else {
recipient, err := types.ParseJID(arg)
if err != nil {
fmt.Printf("invalid JID %s: %v", arg, err)
return recipient, pkgError.ErrInvalidJID
} else if recipient.User == "" {
fmt.Printf("invalid JID %v: no server specified", arg)
return recipient, pkgError.ErrInvalidJID
}
return recipient, nil
}
recipient, err := types.ParseJID(arg)
if err != nil {
fmt.Printf("invalid JID %s: %v", arg, err)
return recipient, pkgError.ErrInvalidJID
}
if recipient.User == "" {
fmt.Printf("invalid JID %v: no server specified", arg)
return recipient, pkgError.ErrInvalidJID
}
return recipient, nil
}
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/newletter"
"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
}
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) {
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/newletter"
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 {
name: 'AccountAvatar',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
image: null,
loading: false,
@ -12,7 +17,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -45,7 +50,7 @@ export default {
handleReset() {
this.phone = '';
this.image = null;
this.type = 'user';
this.type = window.TYPEUSER;
}
},
template: `
@ -66,19 +71,7 @@ export default {
</div>
<div class="content">
<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">
<label>Preview</label>

24
src/views/components/AccountUserInfo.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'AccountUserInfo',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
//
name: null,
@ -15,7 +20,7 @@ export default {
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -52,7 +57,7 @@ export default {
this.name = null;
this.status = null;
this.devices = [];
this.type = 'user';
this.type = window.TYPEUSER;
}
},
template: `
@ -74,18 +79,7 @@ export default {
</div>
<div class="content">
<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}"
@click="handleSubmit">

26
src/views/components/MessageDelete.js

@ -1,8 +1,13 @@
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'DeleteMessage',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
message_id: '',
loading: false,
@ -10,7 +15,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -48,7 +53,7 @@ export default {
}
},
handleReset() {
this.type = 'user';
this.type = window.TYPEUSER;
this.phone = '';
this.message_id = '';
this.new_message = '';
@ -74,19 +79,8 @@ export default {
</div>
<div class="content">
<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">
<label>Message ID</label>
<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 {
name: 'ReactMessage',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
message_id: '',
emoji: '',
@ -11,7 +16,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -51,7 +56,7 @@ export default {
this.phone = '';
this.message_id = '';
this.emoji = '';
this.type = 'user';
this.type = window.TYPEUSER;
},
},
template: `
@ -74,19 +79,8 @@ export default {
</div>
<div class="content">
<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">
<label>Message ID</label>
<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 {
name: 'Message',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
message_id: '',
loading: false,
@ -10,7 +15,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -49,7 +54,7 @@ export default {
handleReset() {
this.phone = '';
this.message_id = '';
this.type = 'user';
this.type = window.TYPEUSER;
},
},
template: `
@ -71,19 +76,8 @@ export default {
</div>
<div class="content">
<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">
<label> Message ID</label>
<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 {
name: 'UpdateMessage',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
message_id: '',
new_message: '',
@ -11,7 +16,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -49,7 +54,7 @@ export default {
}
},
handleReset() {
this.type = 'user';
this.type = window.TYPEUSER;
this.phone = '';
this.message_id = '';
this.new_message = '';
@ -75,19 +80,8 @@ export default {
</div>
<div class="content">
<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">
<label>Message ID</label>
<input v-model="message_id" type="text" placeholder="Please enter your message id"

115
src/views/components/NewsletterList.js

@ -0,0 +1,115 @@
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 = new FormData();
payload.append("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 ''
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 }}</td>
<td>{{ n.viewer_metadata.role }}</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 {
name: 'Send',
components: {
FormRecipient
},
data() {
return {
phone: '',
type: 'user',
type: window.TYPEUSER,
loading: false,
}
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -49,7 +54,7 @@ export default {
},
handleReset() {
this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_audio").val('');
},
},
@ -72,19 +77,7 @@ export default {
</div>
<div class="content">
<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">
<label>Audio</label>
<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 {
name: 'SendContact',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
card_name: '',
card_phone: '',
@ -11,7 +16,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -58,7 +63,7 @@ export default {
this.phone = '';
this.card_name = '';
this.card_phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
},
},
template: `
@ -80,19 +85,8 @@ export default {
</div>
<div class="content">
<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">
<label>Contact Name</label>
<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 {
name: 'SendFile',
components: {
FormRecipient
},
props: {
maxFileSize: {
type: String,
@ -9,14 +14,14 @@ export default {
data() {
return {
caption: '',
type: 'user',
type: window.TYPEUSER,
phone: '',
loading: false,
}
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -58,7 +63,7 @@ export default {
handleReset() {
this.caption = '';
this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_file").val('');
},
},
@ -82,19 +87,8 @@ export default {
</div>
<div class="content">
<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">
<label>Caption</label>
<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 {
name: 'SendImage',
components: {
FormRecipient
},
data() {
return {
phone: '',
view_once: false,
compress: false,
caption: '',
type: 'user',
type: window.TYPEUSER,
loading: false,
selected_file: null
}
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -60,7 +65,7 @@ export default {
this.compress = false;
this.phone = '';
this.caption = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_image").val('');
},
},
@ -85,19 +90,8 @@ export default {
</div>
<div class="content">
<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">
<label>Caption</label>
<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 {
name: 'SendLocation',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
latitude: '',
longitude: '',
@ -11,7 +16,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -56,7 +61,7 @@ export default {
this.phone = '';
this.latitude = '';
this.longitude = '';
this.type = 'user';
this.type = window.TYPEUSER;
},
},
template: `
@ -78,19 +83,8 @@ export default {
</div>
<div class="content">
<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">
<label>Location Latitude</label>
<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 {
name: 'SendMessage',
components: {
FormRecipient
},
data() {
return {
type: 'user',
type: window.TYPEUSER,
phone: '',
text: '',
reply_message_id: '',
@ -11,7 +16,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -57,7 +62,7 @@ export default {
handleReset() {
this.phone = '';
this.text = '';
this.type = 'user';
this.type = window.TYPEUSER;
this.reply_message_id = '';
},
},
@ -80,19 +85,7 @@ export default {
</div>
<div class="content">
<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">
<label>Reply Message ID</label>
<input v-model="reply_message_id" type="text"

26
src/views/components/SendPoll.js

@ -1,10 +1,15 @@
// export Vue Component
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'SendPoll',
components: {
FormRecipient
},
data() {
return {
phone: '',
type: 'user',
type: window.TYPEUSER,
loading: false,
question: '',
options: ['', ''],
@ -13,7 +18,7 @@ export default {
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -56,7 +61,7 @@ export default {
},
handleReset() {
this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
this.question = '';
this.options = ['', ''];
this.max_vote = 1;
@ -87,19 +92,8 @@ export default {
</div>
<div class="content">
<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">
<label>Question</label>
<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 {
name: 'SendVideo',
components: {
FormRecipient
},
// define props
props: {
maxVideoSize: {
@ -12,14 +17,14 @@ export default {
caption: '',
view_once: false,
compress: false,
type: 'user',
type: window.TYPEUSER,
phone: '',
loading: false,
}
},
computed: {
phone_id() {
return this.type === 'user' ? `${this.phone}@${window.TYPEUSER}` : `${this.phone}@${window.TYPEGROUP}`
return this.phone + this.type;
}
},
methods: {
@ -65,7 +70,7 @@ export default {
this.view_once = false;
this.compress = false;
this.phone = '';
this.type = 'user';
this.type = window.TYPEUSER;
$("#file_video").val('');
},
},
@ -91,19 +96,8 @@ export default {
</div>
<div class="content">
<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">
<label>Caption</label>
<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>
</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">
Account
</div>
@ -98,8 +106,9 @@
</div>
<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) => {
$('body').toast({
position: 'bottom right',
@ -120,7 +129,7 @@
}
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 }}
window.http.defaults.headers.common['Authorization'] = {{ .BasicAuthToken }};
@ -150,6 +159,7 @@
import AccountAvatar from "./components/AccountAvatar.js";
import AccountUserInfo from "./components/AccountUserInfo.js";
import AccountPrivacy from "./components/AccountPrivacy.js";
import NewsletterList from "./components/NewsletterList.js";
const showErrorInfo = (message) => {
$('body').toast({
@ -176,6 +186,7 @@
SendMessage, SendImage, SendFile, SendVideo, SendContact, SendLocation, SendAudio, SendPoll,
MessageDelete, MessageUpdate, MessageReact, MessageRevoke,
GroupList, GroupCreate, GroupJoinWithLink, GroupAddParticipants,
NewsletterList,
AccountAvatar, AccountUserInfo, AccountPrivacy
},
delimiters: ['[[', ']]'],

Loading…
Cancel
Save