From 37792c170491efd6b429998a668bc90c94a3dd0a Mon Sep 17 00:00:00 2001 From: Ritul Date: Tue, 31 Mar 2026 14:08:10 +0530 Subject: [PATCH] Fallback changes, API is not working --- client/src/App.jsx | 2 +- client/src/components/ImagePicker.jsx | 6 +- .../src/components/RegisterBusinessModal.jsx | 49 +------ client/src/components/Sidebar.jsx | 22 +-- client/src/components/TestSmsModal.jsx | 4 +- client/src/components/WhitelistModal.jsx | 2 +- client/src/index.css | 60 ++++---- client/src/pages/Brand.jsx | 16 +-- client/src/pages/Businesses.jsx | 134 ++++++++---------- client/src/pages/Events.jsx | 46 +++--- client/src/pages/GlobalSms.jsx | 14 +- client/src/pages/Providers.jsx | 4 +- client/src/pages/Templates.jsx | 14 +- 13 files changed, 159 insertions(+), 214 deletions(-) diff --git a/client/src/App.jsx b/client/src/App.jsx index 7847e48..981889f 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -42,7 +42,7 @@ function BusinessGuard({ children, isGlobalSmsRoute }) { if (loading) { return (
-
+
); } diff --git a/client/src/components/ImagePicker.jsx b/client/src/components/ImagePicker.jsx index e6ed2cb..df8978e 100644 --- a/client/src/components/ImagePicker.jsx +++ b/client/src/components/ImagePicker.jsx @@ -37,14 +37,14 @@ export default function ImagePicker({ currentImage, onSelect }) { onClick={() => onSelect(img.url)} className={`relative rounded-lg overflow-hidden border-2 aspect-video transition-all ${ isSelected - ? 'border-indigo-600 ring-2 ring-indigo-600 ring-opacity-50 shadow-md' + ? 'border-primary-blue ring-2 ring-primary-blue ring-opacity-50 shadow-md' : 'border-transparent hover:border-gray-300 opacity-80 hover:opacity-100 shadow-sm' }`} > {`brand-pic-${i}`} -
+
{isSelected && ( -
+
)} diff --git a/client/src/components/RegisterBusinessModal.jsx b/client/src/components/RegisterBusinessModal.jsx index ff87f8d..428ebd1 100644 --- a/client/src/components/RegisterBusinessModal.jsx +++ b/client/src/components/RegisterBusinessModal.jsx @@ -1,16 +1,9 @@ import { useState } from 'react'; import apiClient from '../api/client'; -import { - getBusinessDomain, - getBusinessImage, - getBusinessName, - getBusinessTagline, -} from '../utils/businessProfile'; export default function RegisterBusinessModal({ onClose }) { const [url, setUrl] = useState(''); const [status, setStatus] = useState('idle'); - const [createdBusiness, setCreatedBusiness] = useState(null); const [error, setError] = useState(''); async function handleSubmit(e) { @@ -21,10 +14,9 @@ export default function RegisterBusinessModal({ onClose }) { setError(''); try { - const res = await apiClient.post('/api/businesses', { + await apiClient.post('/api/businesses', { websiteUrl: url.trim(), }); - setCreatedBusiness(res.data); setStatus('success'); } catch (err) { setError(err.response?.data?.error || 'Something went wrong. Please try again.'); @@ -32,45 +24,18 @@ export default function RegisterBusinessModal({ onClose }) { } } - const successName = getBusinessName(createdBusiness); - const successDomain = getBusinessDomain(createdBusiness); - const successTagline = getBusinessTagline(createdBusiness); - const successImage = getBusinessImage(createdBusiness); - return (
-
+
{status === 'success' && (

Business Added!

-

Brand detected and ready for onboarding.

-
-
-
- {successImage ? ( - {successName} - ) : ( - - {successName?.[0]?.toUpperCase() || 'B'} - - )} -
-
-

{successName}

- {successDomain && ( -

{successDomain}

- )} - {successTagline && ( -

{successTagline}

- )} -
-
-
+

Your business has been registered successfully.

@@ -82,7 +47,7 @@ export default function RegisterBusinessModal({ onClose }) {

Add a Business

- Enter the storefront website URL and we'll scrape it to detect the brand, images, and copy you need for onboarding. + Enter the storefront website URL and we'll scrape it to detect the brand and set up your business.

@@ -95,7 +60,7 @@ export default function RegisterBusinessModal({ onClose }) { onChange={(e) => setUrl(e.target.value)} placeholder="https://yourstore.com" disabled={status === 'loading'} - className="w-full px-4 py-2.5 rounded-lg bg-white border border-gray-300 text-gray-900 placeholder-gray-400 font-medium focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:border-transparent transition disabled:opacity-50 text-sm shadow-sm" + className="w-full px-4 py-2.5 rounded-lg bg-white border border-gray-300 text-gray-900 placeholder-gray-400 font-medium focus:outline-none focus:ring-2 focus:ring-primary-blue focus:border-transparent transition disabled:opacity-50 text-sm shadow-sm" required />
@@ -116,7 +81,7 @@ export default function RegisterBusinessModal({ onClose }) { {activeBusiness && (
-
+
{activeBusiness.brandName?.[0]?.toUpperCase() || 'B'}
@@ -161,7 +161,7 @@ export default function Sidebar() { {item.enabled ? ( {SVG_ICONS[item.id]} {item.label} @@ -203,12 +203,12 @@ export default function Sidebar() { {item.substeps.map((substep) => (
- {substep.active &&
} + {substep.active &&
}
diff --git a/client/src/components/TestSmsModal.jsx b/client/src/components/TestSmsModal.jsx index 8a4e6f2..155b184 100644 --- a/client/src/components/TestSmsModal.jsx +++ b/client/src/components/TestSmsModal.jsx @@ -28,7 +28,7 @@ export default function TestSmsModal({ businessId, template, onClose }) { return (
-
+
📱
@@ -52,7 +52,7 @@ export default function TestSmsModal({ businessId, template, onClose }) { value={toNumber} onChange={e => setToNumber(e.target.value)} placeholder="e.g. 919876543210 (with country code)" - className="w-full px-4 py-2.5 rounded-lg bg-gray-50 border border-gray-300 font-mono text-gray-900 placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-600 text-sm" + className="w-full px-4 py-2.5 rounded-lg bg-gray-50 border border-gray-300 font-mono text-gray-900 placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-primary-blue text-sm" autoFocus required /> diff --git a/client/src/components/WhitelistModal.jsx b/client/src/components/WhitelistModal.jsx index 24b3ea7..f28d9e8 100644 --- a/client/src/components/WhitelistModal.jsx +++ b/client/src/components/WhitelistModal.jsx @@ -104,7 +104,7 @@ export default function WhitelistModal({ businessId, template, boundProfile, onC return (
-
+
diff --git a/client/src/index.css b/client/src/index.css index a7ff865..56acdf9 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -3,38 +3,38 @@ @import "tailwindcss"; @theme { - --color-primary-blue: #4F5BD5; - --color-primary-dark: #2F3DB9; - --color-link-blue: #5B72D7; + --color-primary-blue: #3838C4; + --color-primary-dark: #2B2BA3; + --color-link-blue: #4E4ED6; --color-page-bg: #F5F6F8; --color-surface-white: #FFFFFF; - --color-table-header: #F4F5F7; - --color-pagination-bg: #F8F9FB; - --color-refresh-hover: #F4F6FF; - --color-refresh-active: #E9EDFF; - --color-row-hover: #EEF0F8; - --color-text-primary: #3F434C; - --color-text-muted: #8B9098; - --color-header-text: #4B4F57; - --color-channel-name: #61656D; - --color-border-main: #E2E5EA; - --color-border-soft: #ECEFF3; - --color-item-border: #ECEEF2; - --color-badge-bg: #F0FAEF; - --color-badge-text: #5FA05A; - --color-badge-border: #9FCF9B; - --color-delayed-bg: #FFF1F0; - --color-delayed-text: #D94F4F; - --color-delayed-border: #F5A5A5; - --color-tags-bg: #FFF8F3; - --color-tags-text: #E58D4F; - --color-tags-border: #F2B17F; - --color-error-text: #C62828; - --color-sla-green: #4CAF50; - --color-sla-grey: #BDBDBD; - --color-spinner-track: #D8DEFE; - --color-placeholder-bg: #E0E0E0; - --color-empty-bg: #FAFAFA; + --color-table-header: #F9FAFB; + --color-pagination-bg: #FFFFFF; + --color-refresh-hover: #F0F0FA; + --color-refresh-active: #E0E0F5; + --color-row-hover: #F9FAFB; + --color-text-primary: #1F2937; + --color-text-muted: #6B7280; + --color-header-text: #4B5563; + --color-channel-name: #4B5563; + --color-border-main: #E5E7EB; + --color-border-soft: #F3F4F6; + --color-item-border: #E5E7EB; + --color-badge-bg: #F0FDF4; + --color-badge-text: #166534; + --color-badge-border: #BBF7D0; + --color-delayed-bg: #FEF2F2; + --color-delayed-text: #991B1B; + --color-delayed-border: #FECACA; + --color-tags-bg: #FFFBEB; + --color-tags-text: #92400E; + --color-tags-border: #FDE68A; + --color-error-text: #DC2626; + --color-sla-green: #22C55E; + --color-sla-grey: #D1D5DB; + --color-spinner-track: #E0E7FF; + --color-placeholder-bg: #D1D5DB; + --color-empty-bg: #F9FAFB; } :root { diff --git a/client/src/pages/Brand.jsx b/client/src/pages/Brand.jsx index a6b9194..b87b026 100644 --- a/client/src/pages/Brand.jsx +++ b/client/src/pages/Brand.jsx @@ -13,7 +13,7 @@ const NAV_CARDS = [ function DeleteConfirmModal({ brandName, onCancel, onConfirm, deleting }) { return (
-
+
🗑
@@ -65,7 +65,7 @@ export default function Brand() { if (loading) { return (
-
+
); } @@ -75,7 +75,7 @@ export default function Brand() { return (
-
+
S

SMS Template Extension

@@ -84,7 +84,7 @@ export default function Brand() {

@@ -100,13 +100,13 @@ export default function Brand() {
{/* Brand header card */} -
+

{brand.brandName}

{brand.domain}

- + {brand.tone} @@ -156,7 +156,7 @@ export default function Brand() { {/* Brand images */} {brand.relevantImagePaths?.length > 0 && ( -
+

Brand Images

{brand.relevantImagePaths.map((url, i) => ( @@ -182,7 +182,7 @@ export default function Brand() {
{card.icon}

{card.label}

diff --git a/client/src/pages/Businesses.jsx b/client/src/pages/Businesses.jsx index 5848a99..b4a1d58 100644 --- a/client/src/pages/Businesses.jsx +++ b/client/src/pages/Businesses.jsx @@ -15,7 +15,7 @@ import { function DeleteConfirmModal({ businessName, onCancel, onConfirm, deleting }) { return (
-
+
🗑
@@ -52,21 +52,21 @@ function BusinessCreatedModal({ business, onClose }) { return (
-
+

Business Added!

Your business is ready for onboarding.

-
+
-
+
{image ? ( {name} ) : ( - {name?.[0]?.toUpperCase() || 'B'} + {name?.[0]?.toUpperCase() || 'B'} )}
-

{name}

+

{name}

{domain &&

{domain}

} {tagline &&

{tagline}

}
@@ -74,7 +74,7 @@ function BusinessCreatedModal({ business, onClose }) {
@@ -89,13 +89,13 @@ function SalesChannelCard({ channel, disabled, onImport }) { const image = getBusinessImage(channel); return ( -
+
-
+
{image ? ( {name} ) : ( - {name?.[0]?.toUpperCase() || 'S'} + {name?.[0]?.toUpperCase() || 'S'} )}
@@ -126,7 +126,6 @@ export default function Businesses() { const [salesChannels, setSalesChannels] = useState([]); const [loading, setLoading] = useState(true); const [salesChannelsStatus, setSalesChannelsStatus] = useState('loading'); - const [salesChannelsError, setSalesChannelsError] = useState(''); const [salesChannelQuery, setSalesChannelQuery] = useState(''); const [selectingBusinessId, setSelectingBusinessId] = useState(''); const [creatingSalesChannelId, setCreatingSalesChannelId] = useState(''); @@ -147,6 +146,7 @@ export default function Businesses() { const availableSalesChannels = useMemo(() => ( salesChannels.filter((channel) => !configuredApplicationIds.has(getChannelId(channel))) ), [configuredApplicationIds, salesChannels]); + const showSalesChannelsSection = salesChannelsStatus === 'success' && availableSalesChannels.length > 0; const filteredSalesChannels = useMemo(() => { const query = salesChannelQuery.trim().toLowerCase(); @@ -174,7 +174,6 @@ export default function Businesses() { const load = useCallback(async () => { setLoading(true); setError(''); - setSalesChannelsError(''); try { const [businessesRes, salesChannelsRes] = await Promise.allSettled([ @@ -189,9 +188,6 @@ export default function Businesses() { if (salesChannelsRes.status === 'rejected') { setSalesChannels([]); setSalesChannelsStatus('error'); - setSalesChannelsError( - salesChannelsRes.reason?.message || 'Active sales channels could not be loaded right now.' - ); } } finally { setLoading(false); @@ -218,13 +214,12 @@ export default function Businesses() { if (!applicationId) return; if (!channel.websiteUrl) { - setSalesChannelsError('A website URL could not be derived from this sales channel. Please use Add Business and enter the URL manually.'); + setError('A website URL could not be derived from this sales channel. Please use Add Business and enter the URL manually.'); return; } setCreatingSalesChannelId(applicationId); setError(''); - setSalesChannelsError(''); try { const res = await apiClient.post('/api/businesses', { @@ -258,7 +253,7 @@ export default function Businesses() { if (loading) { return (
-
+
); } @@ -272,12 +267,14 @@ export default function Businesses() { {businesses.length > 0 ? 'Your Businesses' : 'Set Up Your First Business'}

- Import from an active sales channel when available, or use the website URL fallback to scrape manually. + {showSalesChannelsSection + ? 'Import from an active sales channel when available, or use the website URL fallback to scrape manually.' + : 'Add a storefront URL and we’ll scrape it to set up your business.'}

@@ -301,7 +298,7 @@ export default function Businesses() { {businesses.map((biz) => (
- Click to manage → + Click to manage →
) : ( -
+

No configured businesses yet.

-

Import from an active sales channel below, or use Add Business to enter a storefront URL manually.

+

Use Add Business to enter a storefront URL and get started.

)} + {showSalesChannelsSection && (
@@ -366,64 +364,46 @@ export default function Businesses() {
- - {salesChannelsError && ( -
- {salesChannelsError} +
+
+ + setSalesChannelQuery(e.target.value)} + placeholder="Search by channel name or domain" + className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm text-gray-900 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:ring-primary-blue focus:border-transparent" + />
- )} - {salesChannelsStatus === 'loading' ? ( -
-
-

Loading active sales channels…

+
+ {filteredSalesChannels.map((channel) => { + const channelId = getChannelId(channel); + return ( + handleCreateFromSalesChannel(channel)} + /> + ); + })}
- ) : availableSalesChannels.length > 0 ? ( -
-
- - setSalesChannelQuery(e.target.value)} - placeholder="Search by channel name or domain" - className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm text-gray-900 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:border-transparent" - /> + + {filteredSalesChannels.length === 0 && ( +
+

No active sales channels matched your search.

+

Use the website URL fallback if you want to scrape a storefront directly.

- -
- {filteredSalesChannels.map((channel) => { - const channelId = getChannelId(channel); - return ( - handleCreateFromSalesChannel(channel)} - /> - ); - })} -
- - {filteredSalesChannels.length === 0 && ( -
-

No active sales channels matched your search.

-

Use the website URL fallback if you want to scrape a storefront directly.

-
- )} -
- ) : ( -
-

No active sales channels are available right now.

-

Use Add Business to enter a website URL manually and keep moving.

-
- )} + )} +
+ )}
{showModal && ( diff --git a/client/src/pages/Events.jsx b/client/src/pages/Events.jsx index 57f7c3b..43d7cdb 100644 --- a/client/src/pages/Events.jsx +++ b/client/src/pages/Events.jsx @@ -507,7 +507,7 @@ export default function Events() { if (loading) { return (
-
+
); } @@ -533,7 +533,7 @@ export default function Events() { value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="Search events" - className="w-full rounded-xl border border-gray-300 bg-white py-3 pl-11 pr-10 text-sm font-medium text-gray-900 placeholder-gray-400 shadow-sm transition focus:border-indigo-300 focus:outline-none focus:ring-2 focus:ring-indigo-100" + className="w-full rounded-lg border border-gray-300 bg-white py-3 pl-11 pr-10 text-sm font-medium text-gray-900 placeholder-gray-400 shadow-sm transition focus:border-primary-blue focus:outline-none focus:ring-2 focus:ring-indigo-100" /> {searchTerm && ( @@ -597,7 +597,7 @@ export default function Events() { )} {groupedEvents.length === 0 ? ( -
+

No events match your search.

Try a different keyword or clear the search to see the full lifecycle list.

@@ -607,7 +607,7 @@ export default function Events() { const isExpanded = searchTerm.trim() ? true : !!expandedGroups[group.id]; return ( -
+
{openVariableMenuKey === variantKey && ( -
+

Insert DLT Variable

@@ -807,10 +807,10 @@ export default function Events() { type="button" onMouseDown={(e) => e.preventDefault()} onClick={() => insertVariableToken(event.slug, index, option.token)} - className="w-full px-4 py-3 text-left hover:bg-indigo-50 transition flex items-center justify-between gap-3" + className="w-full px-4 py-3 text-left hover:bg-refresh-hover transition flex items-center justify-between gap-3" > {option.label} - {option.token} + {option.token} ))}
@@ -831,10 +831,10 @@ export default function Events() { onSelect={(e) => trackTextareaSelection(variantKey, e.target)} onKeyUp={(e) => trackTextareaSelection(variantKey, e.target)} rows={4} - className={`w-full rounded-xl border px-4 py-3 text-sm text-gray-800 font-mono leading-relaxed resize-y focus:outline-none focus:ring-2 ${ + className={`w-full rounded-lg border px-4 py-3 text-sm text-gray-800 font-mono leading-relaxed resize-y focus:outline-none focus:ring-2 ${ isEdited ? 'border-amber-200 bg-amber-50/40 focus:ring-amber-200 focus:border-amber-300' - : 'border-gray-200 bg-gray-50 focus:ring-indigo-100 focus:border-indigo-300' + : 'border-gray-200 bg-gray-50 focus:ring-indigo-100 focus:border-primary-blue' }`} /> @@ -847,7 +847,7 @@ export default function Events() { }`}> {currentText.length} / {MAX_SMS_LENGTH} - + DLT vars: {dltTokenCount}
@@ -899,7 +899,7 @@ export default function Events() { @@ -925,7 +925,7 @@ export default function Events() { @@ -310,7 +310,7 @@ export default function GlobalSms() { profiles.map(p => { const isActive = p.id === activeProfileId; return ( -
+

{p.name}

@@ -358,15 +358,15 @@ export default function GlobalSms() { ); }) ) : ( -
+

No cURL profiles configured yet.

)}
{/* Inline Form (Create / Edit) */} -
-
+
+

{editingId ? 'Edit Profile' : 'Add New Profile'}

diff --git a/client/src/pages/Providers.jsx b/client/src/pages/Providers.jsx index 01d433c..537ac11 100644 --- a/client/src/pages/Providers.jsx +++ b/client/src/pages/Providers.jsx @@ -73,7 +73,7 @@ export default function Providers() { if (loading) { return (
-
+
); } @@ -103,7 +103,7 @@ export default function Providers() {
)} - +