This commit is contained in:
parent
cbcac9d1fd
commit
b238e7fc47
@ -695,7 +695,8 @@ async def create_whatsapp_template(
|
||||
"body_param_keys": ["groom_name", "bride_name", ...],
|
||||
"button_type": "URL", # optional button type
|
||||
"button_text": "Visit Website", # optional button label
|
||||
"button_url": "https://...", # optional button URL
|
||||
"button_url": "https://...{{1}}", # optional button URL (use {{1}} for dynamic)
|
||||
"button_param_key": "event_id", # param key for button {{1}} placeholder
|
||||
"fallbacks": { "contact_name": "חבר", ... }
|
||||
}
|
||||
"""
|
||||
@ -711,21 +712,22 @@ async def create_whatsapp_template(
|
||||
raise HTTPException(status_code=400, detail="'friendly_name' is required")
|
||||
|
||||
template = {
|
||||
"meta_name": body.get("meta_name", key),
|
||||
"language_code": body.get("language_code", "he"),
|
||||
"friendly_name": body["friendly_name"],
|
||||
"description": body.get("description", ""),
|
||||
"header_type": body.get("header_type", "TEXT"),
|
||||
"header_text": body.get("header_text", ""),
|
||||
"header_handle": body.get("header_handle", ""),
|
||||
"body_text": body.get("body_text", ""),
|
||||
"header_params": body.get("header_param_keys", []),
|
||||
"body_params": body.get("body_param_keys", []),
|
||||
"button_type": body.get("button_type", ""),
|
||||
"button_text": body.get("button_text", ""),
|
||||
"button_url": body.get("button_url", ""),
|
||||
"fallbacks": body.get("fallbacks", {}),
|
||||
"guest_name_key": body.get("guest_name_key", ""),
|
||||
"meta_name": body.get("meta_name", key),
|
||||
"language_code": body.get("language_code", "he"),
|
||||
"friendly_name": body["friendly_name"],
|
||||
"description": body.get("description", ""),
|
||||
"header_type": body.get("header_type", "TEXT"),
|
||||
"header_text": body.get("header_text", ""),
|
||||
"header_handle": body.get("header_handle", ""),
|
||||
"body_text": body.get("body_text", ""),
|
||||
"header_params": body.get("header_param_keys", []),
|
||||
"body_params": body.get("body_param_keys", []),
|
||||
"button_type": body.get("button_type", ""),
|
||||
"button_text": body.get("button_text", ""),
|
||||
"button_url": body.get("button_url", ""),
|
||||
"button_param_key": body.get("button_param_key", ""),
|
||||
"fallbacks": body.get("fallbacks", {}),
|
||||
"guest_name_key": body.get("guest_name_key", ""),
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
@ -492,13 +492,23 @@ class WhatsAppService:
|
||||
"parameters": [{"type": "text", "text": str(v)} for v in body_values],
|
||||
})
|
||||
|
||||
# Handle static URL button
|
||||
# Handle URL button with dynamic parameters
|
||||
# Meta WhatsApp supports dynamic URL suffixes like: https://example.com/guest/{{1}}
|
||||
# where {{1}} is replaced by a dynamic parameter
|
||||
if button_type == "URL" and button_url:
|
||||
# For URL buttons with dynamic suffixes, extract the dynamic part from params
|
||||
# URL buttons in Meta templates can have a static prefix and dynamic suffix
|
||||
# Example: https://example.com/{1} where {1} is replaced by a param
|
||||
# If no dynamic param, the button is purely static (no parameters needed)
|
||||
pass # Static URL buttons don't need parameters in the API call
|
||||
button_param_key = tpl.get("button_param_key", "")
|
||||
# Check if URL has {{1}} placeholder for dynamic parameter
|
||||
if "{{1}}" in button_url and button_param_key:
|
||||
# Dynamic URL button - need to send the parameter value
|
||||
param_value = str(params.get(button_param_key, "")).strip()
|
||||
if param_value:
|
||||
components.append({
|
||||
"type": "button",
|
||||
"sub_type": "url",
|
||||
"index": "0",
|
||||
"parameters": [{"type": "text", "text": param_value}],
|
||||
})
|
||||
# else: Static URL button - no parameters needed in the API call
|
||||
|
||||
# Handle url_button component if defined in template (legacy dynamic buttons)
|
||||
url_btn = tpl.get("url_button", {})
|
||||
|
||||
@ -229,6 +229,7 @@ def list_templates_for_frontend() -> list:
|
||||
"button_type": tpl.get("button_type", ""),
|
||||
"button_text": tpl.get("button_text", ""),
|
||||
"button_url": tpl.get("button_url", ""),
|
||||
"button_param_key": tpl.get("button_param_key", ""),
|
||||
"guest_name_key": tpl.get("guest_name_key", ""),
|
||||
"url_button": tpl.get("url_button", None),
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ const he = {
|
||||
buttonType: 'סוג כפתור',
|
||||
buttonText: 'טקסט הכפתור',
|
||||
buttonUrl: 'כתובת URL',
|
||||
buttonParamKey: 'פרמטר דינמי עבור {{1}}',
|
||||
uploadImage: 'העלה תמונה',
|
||||
uploading: 'מעלה...',
|
||||
paramMapping: 'מיפוי פרמטרים',
|
||||
@ -51,7 +52,8 @@ const he = {
|
||||
headerHint: 'השתמש ב-{{1}} לשם האורח — השאר ריק אם אין כותרת',
|
||||
headerHandleHint: 'העלה תמונה או הדבק קישור לתמונה מ-Meta Media Library',
|
||||
bodyHint: 'השתמש ב-{{1}}, {{2}}, ... לפרמטרים — בדיוק כמו ב-Meta',
|
||||
buttonUrlHint: 'כתובת URL מלאה, לדוגמה: https://invy.dvirlabs.com',
|
||||
buttonUrlHint: 'לכתובת דינמית השתמש ב-{{1}} בסוף הכתובת, לדוגמה: https://invy.dvirlabs.com/guest/{{1}}',
|
||||
buttonParamHint: 'בחר איזה פרמטר ימולא במקום {{1}} בכתובת הכפתור',
|
||||
keyHint: 'אותיות קטנות, מספרים ו-_ בלבד',
|
||||
metaHint: 'שם מדויק כפי שאושר ב-Meta Business Manager',
|
||||
saved: '✓ התבנית נשמרה בהצלחה!',
|
||||
@ -85,7 +87,7 @@ const EMPTY_FORM = {
|
||||
language: 'he', description: '',
|
||||
headerType: 'TEXT', headerText: '', headerHandle: '',
|
||||
bodyText: '',
|
||||
buttonType: '', buttonText: '', buttonUrl: '',
|
||||
buttonType: '', buttonText: '', buttonUrl: '', buttonParamKey: '',
|
||||
}
|
||||
|
||||
export default function TemplateEditor({ onBack }) {
|
||||
@ -201,18 +203,19 @@ export default function TemplateEditor({ onBack }) {
|
||||
setBPK(tpl.body_params || [])
|
||||
setGuestNameKey(tpl.guest_name_key || '')
|
||||
setForm({
|
||||
key: tpl.key,
|
||||
friendlyName: tpl.friendly_name,
|
||||
metaName: tpl.meta_name,
|
||||
language: tpl.language_code || 'he',
|
||||
description: tpl.description || '',
|
||||
headerType: tpl.header_type || 'TEXT',
|
||||
headerText: tpl.header_text || '',
|
||||
headerHandle: tpl.header_handle || '',
|
||||
bodyText: tpl.body_text || '',
|
||||
buttonType: tpl.button_type || '',
|
||||
buttonText: tpl.button_text || '',
|
||||
buttonUrl: tpl.button_url || '',
|
||||
key: tpl.key,
|
||||
friendlyName: tpl.friendly_name,
|
||||
metaName: tpl.meta_name,
|
||||
language: tpl.language_code || 'he',
|
||||
description: tpl.description || '',
|
||||
headerType: tpl.header_type || 'TEXT',
|
||||
headerText: tpl.header_text || '',
|
||||
headerHandle: tpl.header_handle || '',
|
||||
bodyText: tpl.body_text || '',
|
||||
buttonType: tpl.button_type || '',
|
||||
buttonText: tpl.button_text || '',
|
||||
buttonUrl: tpl.button_url || '',
|
||||
buttonParamKey: tpl.button_param_key || '',
|
||||
})
|
||||
setEditMode(true)
|
||||
setEditingKey(tpl.key)
|
||||
@ -249,6 +252,7 @@ export default function TemplateEditor({ onBack }) {
|
||||
button_type: form.buttonType,
|
||||
button_text: form.buttonText.trim(),
|
||||
button_url: form.buttonUrl.trim(),
|
||||
button_param_key: form.buttonParamKey,
|
||||
fallbacks: Object.fromEntries(PARAM_OPTIONS.map(o => [o.key, o.sample])),
|
||||
guest_name_key: guestNameKey,
|
||||
})
|
||||
@ -453,10 +457,28 @@ export default function TemplateEditor({ onBack }) {
|
||||
<div className="te-field">
|
||||
<label>{he.buttonUrl}</label>
|
||||
<input name="buttonUrl" value={form.buttonUrl}
|
||||
onChange={handleInput} placeholder="https://invy.dvirlabs.com"
|
||||
onChange={handleInput} placeholder="https://invy.dvirlabs.com/guest/{{1}}"
|
||||
disabled={saving} dir="ltr" />
|
||||
<small className="te-hint">{he.buttonUrlHint}</small>
|
||||
</div>
|
||||
{form.buttonUrl.includes('{{1}}') && (
|
||||
<div className="te-field">
|
||||
<label>{he.buttonParamKey}</label>
|
||||
<select
|
||||
name="buttonParamKey"
|
||||
value={form.buttonParamKey}
|
||||
onChange={handleInput}
|
||||
disabled={saving}
|
||||
dir="ltr"
|
||||
>
|
||||
<option value="">— בחר פרמטר —</option>
|
||||
{PARAM_OPTIONS.map(o => (
|
||||
<option key={o.key} value={o.key}>{o.label} ({o.key})</option>
|
||||
))}
|
||||
</select>
|
||||
<small className="te-hint">{he.buttonParamHint}</small>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user