flow_chat 0.4.1 β†’ 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1529,6 +1529,7 @@
1529
1529
  // Extract message content based on type
1530
1530
  let messageText = ''
1531
1531
  let interactive = null
1532
+ let mediaContent = null
1532
1533
 
1533
1534
  switch (messagePayload.type) {
1534
1535
  case 'text':
@@ -1570,25 +1571,48 @@
1570
1571
  }
1571
1572
  break
1572
1573
  case 'image':
1573
- messageText = messagePayload.image.caption || 'Image message'
1574
- // In a real implementation, you might want to show the image
1575
- messageText = `πŸ“· ${messageText}`
1574
+ messageText = messagePayload.image.caption || ''
1575
+ mediaContent = {
1576
+ type: 'image',
1577
+ url: messagePayload.image.link || `https://via.placeholder.com/300x200/25d366/white?text=Image+ID:+${messagePayload.image.id || 'media_123'}`,
1578
+ caption: messagePayload.image.caption
1579
+ }
1576
1580
  break
1577
1581
  case 'document':
1578
- messageText = messagePayload.document.caption || messagePayload.document.filename || 'Document'
1579
- messageText = `πŸ“„ ${messageText}`
1582
+ messageText = messagePayload.document.caption || ''
1583
+ mediaContent = {
1584
+ type: 'document',
1585
+ url: messagePayload.document.link,
1586
+ filename: messagePayload.document.filename || 'document.pdf',
1587
+ caption: messagePayload.document.caption
1588
+ }
1580
1589
  break
1581
1590
  case 'audio':
1582
- messageText = '🎡 Audio message'
1591
+ messageText = ''
1592
+ mediaContent = {
1593
+ type: 'audio',
1594
+ url: messagePayload.audio.link || `data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmkcBzuU2e+saDUGOWOJ6+2SV0gYKT2L5zJAGyJH4f2GHz+7zJMxtx9R5Dsl`
1595
+ }
1583
1596
  break
1584
1597
  case 'video':
1585
- messageText = messagePayload.video.caption || 'Video message'
1586
- messageText = `πŸŽ₯ ${messageText}`
1598
+ messageText = messagePayload.video.caption || ''
1599
+ mediaContent = {
1600
+ type: 'video',
1601
+ url: messagePayload.video.link || `https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4`,
1602
+ caption: messagePayload.video.caption
1603
+ }
1587
1604
  break
1588
1605
  case 'location':
1589
1606
  const loc = messagePayload.location
1590
- messageText = `πŸ“ Location: ${loc.name || 'Shared location'}`
1607
+ messageText = loc.name || 'Shared location'
1591
1608
  if (loc.address) messageText += `\n${loc.address}`
1609
+ mediaContent = {
1610
+ type: 'location',
1611
+ latitude: loc.latitude || 0,
1612
+ longitude: loc.longitude || 0,
1613
+ name: loc.name,
1614
+ address: loc.address
1615
+ }
1592
1616
  break
1593
1617
  default:
1594
1618
  messageText = `Unsupported message type: ${messagePayload.type}`
@@ -1596,16 +1620,235 @@
1596
1620
  }
1597
1621
 
1598
1622
  // Add the simulated message to the chat
1599
- addMessage(messageText, false, messagePayload.type, interactive)
1623
+ addMessage(messageText, false, messagePayload.type, interactive, mediaContent)
1600
1624
  }
1601
1625
 
1602
- function addMessage(content, isOutgoing = false, type = 'text', interactive = null) {
1626
+ function addMessage(content, isOutgoing = false, type = 'text', interactive = null, mediaContent = null) {
1603
1627
  const messageDiv = document.createElement('div')
1604
1628
  messageDiv.className = `message ${isOutgoing ? 'outgoing' : 'incoming'}`
1605
1629
 
1606
1630
  const bubbleDiv = document.createElement('div')
1607
1631
  bubbleDiv.className = 'message-bubble'
1608
- bubbleDiv.textContent = content
1632
+
1633
+ // Handle media content first
1634
+ if (mediaContent) {
1635
+ const mediaContainer = document.createElement('div')
1636
+ mediaContainer.className = 'media-container'
1637
+ mediaContainer.style.marginBottom = content ? '8px' : '0'
1638
+
1639
+ switch (mediaContent.type) {
1640
+ case 'image':
1641
+ const img = document.createElement('img')
1642
+ img.src = mediaContent.url
1643
+ img.style.maxWidth = '100%'
1644
+ img.style.height = 'auto'
1645
+ img.style.borderRadius = '8px'
1646
+ img.style.display = 'block'
1647
+ img.alt = mediaContent.caption || 'Image'
1648
+ img.onerror = function() {
1649
+ this.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjBmMGYwIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPvCfk7cgSW1hZ2U8L3RleHQ+PC9zdmc+'
1650
+ this.style.border = '1px solid #e0e0e0'
1651
+ }
1652
+ mediaContainer.appendChild(img)
1653
+ break
1654
+
1655
+ case 'video':
1656
+ const video = document.createElement('video')
1657
+ video.src = mediaContent.url
1658
+ video.controls = true
1659
+ video.style.maxWidth = '100%'
1660
+ video.style.height = 'auto'
1661
+ video.style.borderRadius = '8px'
1662
+ video.style.display = 'block'
1663
+ video.preload = 'metadata'
1664
+ video.onerror = function() {
1665
+ const placeholder = document.createElement('div')
1666
+ placeholder.style.width = '300px'
1667
+ placeholder.style.height = '200px'
1668
+ placeholder.style.backgroundColor = '#f0f0f0'
1669
+ placeholder.style.border = '1px solid #e0e0e0'
1670
+ placeholder.style.borderRadius = '8px'
1671
+ placeholder.style.display = 'flex'
1672
+ placeholder.style.alignItems = 'center'
1673
+ placeholder.style.justifyContent = 'center'
1674
+ placeholder.style.color = '#999'
1675
+ placeholder.style.fontSize = '14px'
1676
+ placeholder.textContent = 'πŸŽ₯ Video'
1677
+ mediaContainer.replaceChild(placeholder, video)
1678
+ }
1679
+ mediaContainer.appendChild(video)
1680
+ break
1681
+
1682
+ case 'audio':
1683
+ const audio = document.createElement('audio')
1684
+ audio.src = mediaContent.url
1685
+ audio.controls = true
1686
+ audio.style.width = '100%'
1687
+ audio.style.maxWidth = '300px'
1688
+ audio.preload = 'metadata'
1689
+ audio.onerror = function() {
1690
+ const placeholder = document.createElement('div')
1691
+ placeholder.style.padding = '12px 16px'
1692
+ placeholder.style.backgroundColor = '#f0f0f0'
1693
+ placeholder.style.border = '1px solid #e0e0e0'
1694
+ placeholder.style.borderRadius = '8px'
1695
+ placeholder.style.display = 'flex'
1696
+ placeholder.style.alignItems = 'center'
1697
+ placeholder.style.gap = '8px'
1698
+ placeholder.style.color = '#666'
1699
+ placeholder.style.fontSize = '14px'
1700
+ placeholder.innerHTML = '🎡 <span>Audio message</span>'
1701
+ mediaContainer.replaceChild(placeholder, audio)
1702
+ }
1703
+ mediaContainer.appendChild(audio)
1704
+ break
1705
+
1706
+ case 'document':
1707
+ const docContainer = document.createElement('div')
1708
+ docContainer.style.padding = '12px 16px'
1709
+ docContainer.style.backgroundColor = '#f8f9fa'
1710
+ docContainer.style.border = '1px solid #e0e0e0'
1711
+ docContainer.style.borderRadius = '8px'
1712
+ docContainer.style.display = 'flex'
1713
+ docContainer.style.alignItems = 'center'
1714
+ docContainer.style.gap = '12px'
1715
+ docContainer.style.cursor = 'pointer'
1716
+ docContainer.style.transition = 'background-color 0.2s'
1717
+
1718
+ const docIcon = document.createElement('div')
1719
+ docIcon.style.fontSize = '24px'
1720
+ docIcon.textContent = getDocumentIcon(mediaContent.filename)
1721
+
1722
+ const docInfo = document.createElement('div')
1723
+ docInfo.style.flex = '1'
1724
+ docInfo.style.minWidth = '0'
1725
+
1726
+ const docName = document.createElement('div')
1727
+ docName.style.fontWeight = '600'
1728
+ docName.style.fontSize = '14px'
1729
+ docName.style.color = '#333'
1730
+ docName.style.overflow = 'hidden'
1731
+ docName.style.textOverflow = 'ellipsis'
1732
+ docName.style.whiteSpace = 'nowrap'
1733
+ docName.textContent = mediaContent.filename
1734
+
1735
+ const docType = document.createElement('div')
1736
+ docType.style.fontSize = '12px'
1737
+ docType.style.color = '#666'
1738
+ docType.textContent = 'Document'
1739
+
1740
+ docInfo.appendChild(docName)
1741
+ docInfo.appendChild(docType)
1742
+ docContainer.appendChild(docIcon)
1743
+ docContainer.appendChild(docInfo)
1744
+
1745
+ // Add click handler if URL is available
1746
+ if (mediaContent.url) {
1747
+ const downloadIcon = document.createElement('div')
1748
+ downloadIcon.style.fontSize = '18px'
1749
+ downloadIcon.style.color = '#666'
1750
+ downloadIcon.textContent = '⬇️'
1751
+ docContainer.appendChild(downloadIcon)
1752
+
1753
+ docContainer.onclick = () => {
1754
+ if (mediaContent.url.startsWith('http')) {
1755
+ window.open(mediaContent.url, '_blank')
1756
+ }
1757
+ }
1758
+
1759
+ docContainer.onmouseover = () => {
1760
+ docContainer.style.backgroundColor = '#e8f5e8'
1761
+ }
1762
+ docContainer.onmouseout = () => {
1763
+ docContainer.style.backgroundColor = '#f8f9fa'
1764
+ }
1765
+ }
1766
+
1767
+ mediaContainer.appendChild(docContainer)
1768
+ break
1769
+
1770
+ case 'location':
1771
+ const locationContainer = document.createElement('div')
1772
+ locationContainer.style.border = '1px solid #e0e0e0'
1773
+ locationContainer.style.borderRadius = '8px'
1774
+ locationContainer.style.overflow = 'hidden'
1775
+ locationContainer.style.maxWidth = '300px'
1776
+
1777
+ // Create a simple map-like visualization
1778
+ const mapDiv = document.createElement('div')
1779
+ mapDiv.style.height = '150px'
1780
+ mapDiv.style.background = 'linear-gradient(135deg, #a8e6cf 0%, #dcedc1 100%)'
1781
+ mapDiv.style.position = 'relative'
1782
+ mapDiv.style.display = 'flex'
1783
+ mapDiv.style.alignItems = 'center'
1784
+ mapDiv.style.justifyContent = 'center'
1785
+ mapDiv.style.fontSize = '32px'
1786
+ mapDiv.textContent = 'πŸ“'
1787
+
1788
+ // Add coordinate text
1789
+ const coordDiv = document.createElement('div')
1790
+ coordDiv.style.position = 'absolute'
1791
+ coordDiv.style.bottom = '8px'
1792
+ coordDiv.style.right = '8px'
1793
+ coordDiv.style.background = 'rgba(255,255,255,0.9)'
1794
+ coordDiv.style.padding = '4px 8px'
1795
+ coordDiv.style.borderRadius = '4px'
1796
+ coordDiv.style.fontSize = '10px'
1797
+ coordDiv.style.color = '#666'
1798
+ coordDiv.style.fontFamily = 'monospace'
1799
+ coordDiv.textContent = `${mediaContent.latitude.toFixed(4)}, ${mediaContent.longitude.toFixed(4)}`
1800
+ mapDiv.appendChild(coordDiv)
1801
+
1802
+ const locationInfo = document.createElement('div')
1803
+ locationInfo.style.padding = '12px'
1804
+ locationInfo.style.backgroundColor = 'white'
1805
+
1806
+ if (mediaContent.name) {
1807
+ const nameDiv = document.createElement('div')
1808
+ nameDiv.style.fontWeight = '600'
1809
+ nameDiv.style.fontSize = '14px'
1810
+ nameDiv.style.color = '#333'
1811
+ nameDiv.style.marginBottom = '4px'
1812
+ nameDiv.textContent = mediaContent.name
1813
+ locationInfo.appendChild(nameDiv)
1814
+ }
1815
+
1816
+ if (mediaContent.address) {
1817
+ const addressDiv = document.createElement('div')
1818
+ addressDiv.style.fontSize = '12px'
1819
+ addressDiv.style.color = '#666'
1820
+ addressDiv.textContent = mediaContent.address
1821
+ locationInfo.appendChild(addressDiv)
1822
+ }
1823
+
1824
+ // Add link to open in maps
1825
+ const mapsLink = document.createElement('div')
1826
+ mapsLink.style.fontSize = '12px'
1827
+ mapsLink.style.color = '#25d366'
1828
+ mapsLink.style.cursor = 'pointer'
1829
+ mapsLink.style.marginTop = '8px'
1830
+ mapsLink.textContent = 'πŸ—ΊοΈ View in Maps'
1831
+ mapsLink.onclick = () => {
1832
+ const url = `https://www.google.com/maps?q=${mediaContent.latitude},${mediaContent.longitude}`
1833
+ window.open(url, '_blank')
1834
+ }
1835
+ locationInfo.appendChild(mapsLink)
1836
+
1837
+ locationContainer.appendChild(mapDiv)
1838
+ locationContainer.appendChild(locationInfo)
1839
+ mediaContainer.appendChild(locationContainer)
1840
+ break
1841
+ }
1842
+
1843
+ bubbleDiv.appendChild(mediaContainer)
1844
+ }
1845
+
1846
+ // Add text content if present
1847
+ if (content) {
1848
+ const textDiv = document.createElement('div')
1849
+ textDiv.textContent = content
1850
+ bubbleDiv.appendChild(textDiv)
1851
+ }
1609
1852
 
1610
1853
  messageDiv.appendChild(bubbleDiv)
1611
1854
 
@@ -1640,10 +1883,42 @@
1640
1883
  bubbleDiv.appendChild(buttonsDiv)
1641
1884
  }
1642
1885
 
1886
+ messageDiv.appendChild(bubbleDiv)
1887
+
1643
1888
  elements.messagesArea.appendChild(messageDiv)
1644
1889
  elements.messagesArea.scrollTop = elements.messagesArea.scrollHeight
1645
1890
  }
1646
1891
 
1892
+ function getDocumentIcon(filename) {
1893
+ if (!filename) return 'πŸ“„'
1894
+
1895
+ const ext = filename.split('.').pop().toLowerCase()
1896
+
1897
+ const iconMap = {
1898
+ 'pdf': 'πŸ“•',
1899
+ 'doc': 'πŸ“˜',
1900
+ 'docx': 'πŸ“˜',
1901
+ 'xls': 'πŸ“—',
1902
+ 'xlsx': 'πŸ“—',
1903
+ 'ppt': 'πŸ“™',
1904
+ 'pptx': 'πŸ“™',
1905
+ 'txt': 'πŸ“',
1906
+ 'zip': 'πŸ—œοΈ',
1907
+ 'rar': 'πŸ—œοΈ',
1908
+ '7z': 'πŸ—œοΈ',
1909
+ 'mp3': '🎡',
1910
+ 'wav': '🎡',
1911
+ 'mp4': 'πŸŽ₯',
1912
+ 'avi': 'πŸŽ₯',
1913
+ 'jpg': 'πŸ–ΌοΈ',
1914
+ 'jpeg': 'πŸ–ΌοΈ',
1915
+ 'png': 'πŸ–ΌοΈ',
1916
+ 'gif': 'πŸ–ΌοΈ'
1917
+ }
1918
+
1919
+ return iconMap[ext] || 'πŸ“„'
1920
+ }
1921
+
1647
1922
  function addInfoMessage(content) {
1648
1923
  const messageDiv = document.createElement('div')
1649
1924
  messageDiv.className = 'message incoming'
@@ -14,7 +14,7 @@ module FlowChat
14
14
 
15
15
  # Add timestamp for all requests
16
16
  context["request.timestamp"] = Time.current.iso8601
17
-
17
+
18
18
  # Set a basic message_id (can be enhanced based on actual Nsano implementation)
19
19
  context["request.message_id"] = SecureRandom.uuid
20
20
 
@@ -24,4 +24,4 @@ module FlowChat
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -59,19 +59,19 @@ module FlowChat
59
59
 
60
60
  # For USSD, we append the media URL to the message
61
61
  media_text = case media_type.to_sym
62
- when :image
63
- "πŸ“· Image: #{media_url}"
64
- when :document
65
- "πŸ“„ Document: #{media_url}"
66
- when :audio
67
- "🎡 Audio: #{media_url}"
68
- when :video
69
- "πŸŽ₯ Video: #{media_url}"
70
- when :sticker
71
- "😊 Sticker: #{media_url}"
72
- else
73
- "πŸ“Ž Media: #{media_url}"
74
- end
62
+ when :image
63
+ "πŸ“· Image: #{media_url}"
64
+ when :document
65
+ "πŸ“„ Document: #{media_url}"
66
+ when :audio
67
+ "🎡 Audio: #{media_url}"
68
+ when :video
69
+ "πŸŽ₯ Video: #{media_url}"
70
+ when :sticker
71
+ "😊 Sticker: #{media_url}"
72
+ else
73
+ "πŸ“Ž Media: #{media_url}"
74
+ end
75
75
 
76
76
  # Combine message with media information
77
77
  "#{message}\n\n#{media_text}"
@@ -1,3 +1,3 @@
1
1
  module FlowChat
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -61,4 +61,4 @@ module FlowChat
61
61
  end
62
62
  end
63
63
  end
64
- end
64
+ end