Skip to content

Commit bd31c90

Browse files
authored
Merge pull request #115 from Bit-Apps-Pro/feat/add-line
fix: Line fieldmapping required value
2 parents d86e132 + dce675f commit bd31c90

File tree

5 files changed

+318
-223
lines changed

5 files changed

+318
-223
lines changed

frontend-dev/src/components/AllIntegrations/Line/Line.jsx

Lines changed: 68 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable no-unused-expressions */
21
import { useState } from 'react'
32
import 'react-multiple-select-dropdown-lite/dist/index.css'
43
import { useNavigate, useParams } from 'react-router-dom'
@@ -17,6 +16,67 @@ import {
1716
import LineIntegLayout from './LineIntegLayout'
1817
import BackIcn from '../../../Icons/BackIcn'
1918

19+
const messageTypes = [
20+
{ name: 'sendPushMessage', label: __('Send a Push Message', 'bit-integrations'), is_pro: false },
21+
{ name: 'sendReplyMessage', label: __('Send a Reply Message', 'bit-integrations'), is_pro: true },
22+
{
23+
name: 'sendBroadcastMessage',
24+
label: __('Send Broadcast Message', 'bit-integrations'),
25+
is_pro: true
26+
}
27+
]
28+
29+
const emojisFields = [
30+
{ label: __('Emojis ID', 'bit-integrations'), value: 'emojis_id', required: true },
31+
{ label: __('Product Id', 'bit-integrations'), value: 'product_id', required: true },
32+
{
33+
label: __('Emoji Position (0-based index in text)', 'bit-integrations'),
34+
value: 'index',
35+
required: true
36+
}
37+
]
38+
39+
const stickerFields = [
40+
{ label: __('Sticker ID', 'bit-integrations'), value: 'sticker_id', required: true },
41+
{ label: __('Package Id', 'bit-integrations'), value: 'package_id', required: true }
42+
]
43+
44+
const imageFields = [
45+
{
46+
label: __("Image's Original Content URL", 'bit-integrations'),
47+
value: 'originalContentUrl',
48+
required: true
49+
},
50+
{
51+
label: __("Image's Preview Image URL", 'bit-integrations'),
52+
value: 'previewImageUrl',
53+
required: true
54+
}
55+
]
56+
57+
const audioFields = [
58+
{
59+
label: __("Audio's Original Content URL", 'bit-integrations'),
60+
value: 'originalContentUrl',
61+
required: true
62+
},
63+
{ label: __('Duration', 'bit-integrations'), value: 'duration', required: true }
64+
]
65+
66+
const videoFields = [
67+
{ label: __('Original Content URL', 'bit-integrations'), value: 'originalContentUrl', required: true },
68+
{ label: __('Preview Image URL', 'bit-integrations'), value: 'previewImageUrl', required: true }
69+
]
70+
71+
const locationFields = [
72+
{ label: __('Title', 'bit-integrations'), value: 'title', required: true },
73+
{ label: __('Address', 'bit-integrations'), value: 'address', required: true },
74+
{ label: __('Latitude', 'bit-integrations'), value: 'latitude', required: true },
75+
{ label: __('longitude', 'bit-integrations'), value: 'longitude', required: true }
76+
]
77+
78+
const messageField = [{ label: __('Message', 'bit-integrations'), value: 'message', required: true }]
79+
2080
function Line({ formFields, setFlow, flow, allIntegURL }) {
2181
const navigate = useNavigate()
2282
const { formID } = useParams()
@@ -32,13 +92,13 @@ function Line({ formFields, setFlow, flow, allIntegURL }) {
3292
accessToken: '',
3393
parse_mode: 'HTML',
3494
messageTypes,
35-
emojis_field_map: generateMappedField(emojisFields),
95+
emojis_field_map: generateMappedField(emojisFields, 'emoji'),
3696
message_field_map: generateMappedField(messageField),
37-
sticker_field_map: generateMappedField(stickerFields),
38-
image_field_map: generateMappedField(imageFields),
39-
audio_field_map: generateMappedField(audioFields),
40-
video_field_map: generateMappedField(videoFields),
41-
location_field_map: generateMappedField(locationFields),
97+
sticker_field_map: generateMappedField(stickerFields, 'sticker'),
98+
image_field_map: generateMappedField(imageFields, 'image'),
99+
audio_field_map: generateMappedField(audioFields, 'audio'),
100+
video_field_map: generateMappedField(videoFields, 'video'),
101+
location_field_map: generateMappedField(locationFields, 'location'),
42102
body: '',
43103
actions: {},
44104
sendEmojis: false,
@@ -64,7 +124,7 @@ function Line({ formFields, setFlow, flow, allIntegURL }) {
64124
}
65125
}, 300)
66126

67-
if (val === 3 && !(lineConf?.name || isNextButtonEnabled())) {
127+
if (val === 3 && (!lineConf?.name || !isNextButtonEnabled())) {
68128
const messages = getLineValidationMessages(lineConf)
69129
setSnackbar({
70130
show: true,
@@ -156,64 +216,3 @@ function Line({ formFields, setFlow, flow, allIntegURL }) {
156216
}
157217

158218
export default Line
159-
160-
const messageTypes = [
161-
{ name: 'sendPushMessage', label: __('Send a Push Message', 'bit-integrations'), is_pro: false },
162-
{ name: 'sendReplyMessage', label: __('Send a Reply Message', 'bit-integrations'), is_pro: true },
163-
{
164-
name: 'sendBroadcastMessage',
165-
label: __('Send Broadcast Message', 'bit-integrations'),
166-
is_pro: true
167-
}
168-
]
169-
170-
const emojisFields = [
171-
{ label: __('Emojis ID', 'bit-integrations'), value: 'emojis_id', required: true },
172-
{ label: __('Product Id', 'bit-integrations'), value: 'product_id', required: true },
173-
{
174-
label: __('Emoji Position (0-based index in text)', 'bit-integrations'),
175-
value: 'index',
176-
required: true
177-
}
178-
]
179-
180-
const stickerFields = [
181-
{ label: __('Sticker ID', 'bit-integrations'), value: 'sticker_id', required: true },
182-
{ label: __('Package Id', 'bit-integrations'), value: 'package_id', required: true }
183-
]
184-
185-
const imageFields = [
186-
{
187-
label: __("Image's Original Content URL", 'bit-integrations'),
188-
value: 'originalContentUrl',
189-
required: true
190-
},
191-
{
192-
label: __("Image's Preview Image URL", 'bit-integrations'),
193-
value: 'previewImageUrl',
194-
required: true
195-
}
196-
]
197-
198-
const audioFields = [
199-
{
200-
label: __("Audio's Original Content URL", 'bit-integrations'),
201-
value: 'originalContentUrl',
202-
required: true
203-
},
204-
{ label: __('Duration', 'bit-integrations'), value: 'duration', required: true }
205-
]
206-
207-
const videoFields = [
208-
{ label: __('Original Content URL', 'bit-integrations'), value: 'originalContentUrl', required: true },
209-
{ label: __('Preview Image URL', 'bit-integrations'), value: 'previewImageUrl', required: true }
210-
]
211-
212-
const locationFields = [
213-
{ label: __('Title', 'bit-integrations'), value: 'title', required: true },
214-
{ label: __('Address', 'bit-integrations'), value: 'address', required: true },
215-
{ label: __('Latitude', 'bit-integrations'), value: 'latitude', required: true },
216-
{ label: __('longitude', 'bit-integrations'), value: 'longitude', required: true }
217-
]
218-
219-
const messageField = [{ label: __('Message', 'bit-integrations'), value: 'message', required: true }]

frontend-dev/src/components/AllIntegrations/Line/LineCommonFunc.js

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
/* eslint-disable no-else-return */
21
import { __ } from '../../../Utils/i18nwrap'
32
import bitsFetch from '../../../Utils/bitsFetch'
43

54
export const handleInput = (e, lineConf, setLineConf) => {
65
const { name, value } = e.target
7-
setLineConf(prev => ({ ...prev, ...(value ? { [name]: value } : { [name]: undefined }) }))
6+
setLineConf(prev => ({ ...prev, [name]: value }))
87
}
98

109
export const handleAuthorize = async (
@@ -23,8 +22,6 @@ export const handleAuthorize = async (
2322
setError({})
2423
setIsLoading(true)
2524

26-
setIsLoading(true)
27-
2825
try {
2926
const result = await bitsFetch({ accessToken: confTmp.accessToken }, 'line_authorization')
3027

@@ -63,13 +60,13 @@ const updateFieldMap = (prevConf, type, index, updater) => {
6360
return newConf
6461
}
6562

66-
export const handleFieldMapping = (event, index, _, setConf, type) => {
67-
setConf(prev =>
68-
updateFieldMap(prev, type, index, () => ({
69-
[event.target.name]: event.target.value,
70-
...(event.target.value === 'custom' ? { customValue: '' } : {})
71-
}))
72-
)
63+
export const handleFieldMapping = (event, index, setConf, type) => {
64+
const updateFunction = () => ({
65+
[event.target.name]: event.target.value,
66+
...(event.target.value === 'custom' ? { customValue: '' } : { customValue: undefined })
67+
})
68+
69+
setConf(prev => updateFieldMap(prev, type, index, updateFunction))
7370
}
7471

7572
export const handleCustomValue = (event, index, _, setConf, type) => {
@@ -91,18 +88,67 @@ export const delFieldMap = (index, _, setConf, type) => {
9188
})
9289
}
9390

94-
export const addFieldMap = (i, confTmp, setConf, FieldMappings, mapKey) => {
95-
const groupId = Date.now() + Math.random()
96-
const newFieldMap = FieldMappings.map(field => ({
97-
formField: '',
98-
lineFormField: field.value,
99-
groupId
100-
}))
91+
const FIELD_CATEGORIES = {
92+
sticker: ['sticker_id', 'package_id'],
93+
image: ['originalContentUrl', 'previewImageUrl'],
94+
audio: ['originalContentUrl', 'duration'],
95+
video: ['originalContentUrl', 'previewImageUrl'],
96+
location: ['title', 'address', 'latitude', 'longitude'],
97+
emoji: ['emojis_id', 'product_id', 'index']
98+
}
99+
100+
const getFieldCategory = lineFormField => {
101+
for (const [type, fields] of Object.entries(FIELD_CATEGORIES)) {
102+
if (fields.includes(lineFormField)) {
103+
return type
104+
}
105+
}
106+
return 'default'
107+
}
101108

109+
const generateGroupId = (fieldType, existingFieldMap) => {
110+
if (fieldType === 'audio') {
111+
const existingAudioGroups = [
112+
...new Set(
113+
existingFieldMap.filter(field => field.fieldType === 'audio').map(field => field.groupId)
114+
)
115+
]
116+
return `audio_${existingAudioGroups.length + 1}`
117+
}
118+
const existingGroups = [
119+
...new Set(
120+
existingFieldMap
121+
.filter(field => getFieldCategory(field.lineFormField) === fieldType)
122+
.map(field => field.groupId)
123+
)
124+
]
125+
return `${fieldType}_${existingGroups.length + 1}`
126+
}
127+
128+
export const addFieldMap = (i, confTmp, setConf, FieldMappings, mapKey) => {
102129
setConf(prev => {
103130
const newConf = { ...prev }
104-
105131
if (!Array.isArray(newConf[mapKey])) newConf[mapKey] = []
132+
if (mapKey === 'audio_field_map') {
133+
const fieldType = 'audio'
134+
const groupId = generateGroupId('audio', newConf[mapKey])
135+
const newFieldMap = FieldMappings.map(field => ({
136+
formField: '',
137+
lineFormField: field.value,
138+
groupId,
139+
fieldType: 'audio'
140+
}))
141+
newConf[mapKey].splice(i, 0, ...newFieldMap)
142+
return newConf
143+
}
144+
let fieldType = getFieldCategory(FieldMappings[0].value)
145+
let groupId = generateGroupId(fieldType, newConf[mapKey])
146+
const newFieldMap = FieldMappings.map(field => ({
147+
formField: '',
148+
lineFormField: field.value,
149+
groupId,
150+
fieldType
151+
}))
106152
newConf[mapKey].splice(i, 0, ...newFieldMap)
107153
return newConf
108154
})
@@ -162,13 +208,11 @@ export const getLineValidationMessages = lineConf => {
162208
case 'sendPushMessage':
163209
if (!lineConf.recipientId?.trim())
164210
messages.push(__('Recipient ID is required', 'bit-integrations'))
165-
166211
if (!isMessageFieldConfigured(lineConf))
167212
messages.push(__('Message field mapping is required', 'bit-integrations'))
168213
break
169214
case 'sendReplyMessage':
170215
if (!lineConf.replyToken?.trim()) messages.push(__('Reply Token is required', 'bit-integrations'))
171-
172216
if (!isMessageFieldConfigured(lineConf))
173217
messages.push(__('Message field mapping is required', 'bit-integrations'))
174218
break
@@ -189,9 +233,22 @@ export const getLineValidationMessages = lineConf => {
189233
return messages
190234
}
191235

192-
export const generateMappedField = fields => {
236+
export const generateMappedField = (fields, fieldType = null) => {
193237
const requiredFlds = fields.filter(f => f.required)
194-
return requiredFlds.length
195-
? requiredFlds.map(f => ({ formField: '', lineFormField: f.value }))
196-
: [{ formField: '', lineFormField: '' }]
238+
if (requiredFlds.length) {
239+
const typeToGroupId = {}
240+
return requiredFlds.map(f => {
241+
const actualFieldType = fieldType || getFieldCategory(f.value)
242+
if (!typeToGroupId[actualFieldType]) {
243+
typeToGroupId[actualFieldType] = `${actualFieldType}_1`
244+
}
245+
return {
246+
formField: '',
247+
lineFormField: f.value,
248+
groupId: typeToGroupId[actualFieldType],
249+
fieldType: actualFieldType
250+
}
251+
})
252+
}
253+
return [{ formField: '', lineFormField: '' }]
197254
}

frontend-dev/src/components/AllIntegrations/Line/LineFieldMap.jsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function LineFieldMap({
2727
className="btcd-paper-inp mr-2"
2828
name="formField"
2929
value={field.formField || ''}
30-
onChange={ev => handleFieldMapping(ev, i, lineConf, setLineConf, fieldMapKey)}>
30+
onChange={ev => handleFieldMapping(ev, i, setLineConf, fieldMapKey)}>
3131
<option value="">{__('Select Field', 'bit-integrations')}</option>
3232
<optgroup label={__('Form Fields', 'bit-integrations')}>
3333
{formFields?.map(f => (
@@ -69,11 +69,9 @@ export default function LineFieldMap({
6969

7070
<select
7171
className="btcd-paper-inp"
72-
disabled={isMessageField}
72+
disabled={true}
7373
name="lineFormField"
74-
value={field.lineFormField || ''}
75-
onChange={ev => handleFieldMapping(ev, i, lineConf, setLineConf, fieldMapKey)}>
76-
<option value="">{__('Select Field', 'bit-integrations')}</option>
74+
value={field.lineFormField || ''}>
7775
{Array.isArray(requiredFields) &&
7876
requiredFields.map(({ value, label }, index) => (
7977
<option key={index} value={value}>

frontend-dev/src/components/AllIntegrations/Line/LineIntegLayout.jsx

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,27 @@ export default function LineIntegLayout({ formFields, lineConf, setLineConf, isL
1717
const btcbi = useRecoilValue($btcbi)
1818
const { isPro } = btcbi
1919

20+
const setChange = (value, name) => {
21+
setLineConf(prevConf =>
22+
create(prevConf, draftConf => {
23+
draftConf[name] = value
24+
})
25+
)
26+
}
27+
2028
const handleInput = e => {
21-
const newConf = { ...lineConf }
22-
newConf[e.target.name] = e.target.value
23-
setLineConf(newConf)
29+
setChange(e.target.value, e.target.name)
2430
}
2531

2632
const setMessageBody = val => {
27-
const newConf = { ...lineConf }
28-
newConf.body = val
29-
setLineConf(newConf)
30-
}
31-
const changeActionRun = e => {
32-
const newConf = { ...lineConf }
33-
if (newConf?.body) {
34-
newConf.body = ''
35-
}
36-
newConf.parse_mode = e.target.value
37-
setLineConf(newConf)
33+
setChange(val, 'body')
3834
}
3935

40-
const setChange = (value, name) => {
36+
const changeActionRun = e => {
4137
setLineConf(prevConf =>
4238
create(prevConf, draftConf => {
43-
draftConf[name] = value
39+
if (draftConf.body) draftConf.body = ''
40+
draftConf.parse_mode = e.target.value
4441
})
4542
)
4643
}

0 commit comments

Comments
 (0)