From f19ee2a78a4973f041ebb3b238702be41a7c1748 Mon Sep 17 00:00:00 2001 From: Darian Date: Mon, 9 Mar 2026 11:05:31 +0200 Subject: [PATCH 01/18] fix: builder accordion rmv comp internal state --- .../app/components/banner/BannerBuilder.tsx | 28 ++++++++++----- .../components/offerwall/OfferwallBuilder.tsx | 22 ++++++------ .../redesign/components/BuilderAccordion.tsx | 34 ++++++++----------- .../app/components/widget/WidgetBuilder.tsx | 28 ++++++++++----- frontend/app/routes/banner.tsx | 3 ++ frontend/app/routes/widget.tsx | 3 ++ frontend/app/tailwind.css | 6 +--- 7 files changed, 74 insertions(+), 50 deletions(-) diff --git a/frontend/app/components/banner/BannerBuilder.tsx b/frontend/app/components/banner/BannerBuilder.tsx index 34a369100..b9d25817b 100644 --- a/frontend/app/components/banner/BannerBuilder.tsx +++ b/frontend/app/components/banner/BannerBuilder.tsx @@ -64,17 +64,24 @@ function ContentBuilder({ onRefresh }: Props) { { - uiActions.setActiveSection(isOpen ? 'content' : null) - if (isOpen) { + isOpen={uiState.activeSection === 'content'} + onClick={(isOpen) => { + uiActions.setActiveSection( + isOpen ? 'content' : uiState.appearanceComplete ? null : 'appearance', + ) + }} + onToggle={(e) => { + if (e.currentTarget.open) { uiActions.setContentComplete(true) } }} onRefresh={() => onRefresh('content')} onDone={() => { + uiActions.setActiveSection( + uiState.appearanceComplete ? null : 'appearance', + ) uiActions.setContentComplete(true) }} - initialIsOpen={uiState.activeSection === 'content'} > { - uiActions.setActiveSection(isOpen ? 'appearance' : null) - if (isOpen) { + isOpen={uiState.activeSection === 'appearance'} + onClick={(isOpen: boolean) => { + uiActions.setActiveSection( + isOpen ? 'appearance' : uiState.contentComplete ? null : 'content', + ) + }} + onToggle={(e) => { + if (e.currentTarget.open) { uiActions.setAppearanceComplete(true) } }} onRefresh={() => onRefresh('appearance')} onDone={() => { + uiActions.setActiveSection(null) uiActions.setAppearanceComplete(true) }} - initialIsOpen={uiState.activeSection === 'appearance'} > }> void @@ -30,25 +32,25 @@ export function OfferwallBuilder({ onRefresh }: Props) { function AppearanceBuilder({ onRefresh }: Props) { const uiState = useUIState() - const uiActions = useUIActions() const [snap, profile] = useOfferwallProfile() - const defaultFontIndex = FONT_FAMILY_OPTIONS.findIndex( (option) => option === snap.font.name, ) + useEffect(() => { + const unsubscribe = subscribe(profile, () => { + toolActions.setBuildCompleteStep('filled') + }) + + return unsubscribe + }, []) + return ( { - if (!isOpen) { - uiActions.setAppearanceComplete(true) - toolActions.setBuildCompleteStep('filled') - } - }} onRefresh={onRefresh} - initialIsOpen + isOpen > }> void onDone?: () => void isComplete?: boolean - initialIsOpen?: boolean - onToggle?: (isOpen: boolean) => void + isOpen?: boolean + onClick?: (isOpen: boolean) => void + onToggle?: (e: React.SyntheticEvent) => void children: React.ReactNode } -export const BuilderAccordion: React.FC = ({ +export const BuilderAccordion: React.FC = ({ title, isComplete = false, - initialIsOpen = false, - onToggle, + isOpen = false, + onClick, onRefresh, onDone, + onToggle, children, }) => { - const [isOpen, setIsOpen] = useState(initialIsOpen) - - const handleToggle = (e: React.SyntheticEvent) => { - const isOpen = e.currentTarget.open - setIsOpen(isOpen) - onToggle?.(isOpen) + const handleSummaryClick = (e: React.MouseEvent) => { + e.preventDefault() + onClick?.(!isOpen) } return (
= ({
{ - setIsOpen(false) - onDone() - }} + onClick={onDone} > Done diff --git a/frontend/app/components/widget/WidgetBuilder.tsx b/frontend/app/components/widget/WidgetBuilder.tsx index cf017e711..664b39242 100644 --- a/frontend/app/components/widget/WidgetBuilder.tsx +++ b/frontend/app/components/widget/WidgetBuilder.tsx @@ -60,17 +60,24 @@ function ContentBuilder({ onRefresh }: Props) { { - uiActions.setActiveSection(isOpen ? 'content' : null) - if (isOpen) { + isOpen={uiState.activeSection === 'content'} + onClick={(isOpen) => { + uiActions.setActiveSection( + isOpen ? 'content' : uiState.appearanceComplete ? null : 'appearance', + ) + }} + onToggle={(e) => { + if (e.currentTarget.open) { uiActions.setContentComplete(true) } }} onRefresh={() => onRefresh('content')} onDone={() => { + uiActions.setActiveSection( + uiState.appearanceComplete ? null : 'appearance', + ) uiActions.setContentComplete(true) }} - initialIsOpen={uiState.activeSection === 'content'} > { - uiActions.setActiveSection(isOpen ? 'appearance' : null) - if (isOpen) { + isOpen={uiState.activeSection === 'appearance'} + onClick={(isOpen: boolean) => { + uiActions.setActiveSection( + isOpen ? 'appearance' : uiState.contentComplete ? null : 'content', + ) + }} + onToggle={(e) => { + if (e.currentTarget.open) { uiActions.setAppearanceComplete(true) } }} onRefresh={() => onRefresh('appearance')} onDone={() => { + uiActions.setActiveSection(null) uiActions.setAppearanceComplete(true) }} - initialIsOpen={uiState.activeSection === 'appearance'} > }> { @@ -85,6 +86,7 @@ export default function Banner() { const snap = useSnapshot(toolState) const bannerSnap = useSnapshot(banner) const navigate = useNavigate() + const uiActions = useUIActions() const { save, saveLastAction } = useSaveProfile() const { walletAddressRef, scrollToWalletAddress } = useScrollToWalletAddress() const [isLoading, setIsLoading] = useState(false) @@ -96,6 +98,7 @@ export default function Banner() { useBodyClass('has-fixed-action-bar') useEffect(() => { + uiActions.setActiveSection('content') const unsubscribeUpdates = subscribeProfilesToUpdates() hydrateProfilesFromStorage() const unsubscribeStorage = subscribeProfilesToStorage() diff --git a/frontend/app/routes/widget.tsx b/frontend/app/routes/widget.tsx index 655001d75..f883ef427 100644 --- a/frontend/app/routes/widget.tsx +++ b/frontend/app/routes/widget.tsx @@ -31,6 +31,7 @@ import { persistState, loadState, } from '~/stores/toolStore' +import { useUIActions } from '~/stores/uiStore' import { actions, widget, @@ -82,6 +83,7 @@ export default function Widget() { const snap = useSnapshot(toolState) const widgetSnap = useSnapshot(widget) const navigate = useNavigate() + const uiActions = useUIActions() const { save, saveLastAction } = useSaveProfile() const { walletAddressRef, scrollToWalletAddress } = useScrollToWalletAddress() const [isLoading, setIsLoading] = useState(false) @@ -92,6 +94,7 @@ export default function Widget() { useBodyClass('has-fixed-action-bar') useEffect(() => { + uiActions.setActiveSection('content') const unsubscribeUpdates = subscribeProfilesToUpdates() hydrateProfilesFromStorage() const unsubscribeStorage = subscribeProfilesToStorage() diff --git a/frontend/app/tailwind.css b/frontend/app/tailwind.css index 8a1e54d37..5dcebae43 100644 --- a/frontend/app/tailwind.css +++ b/frontend/app/tailwind.css @@ -75,11 +75,7 @@ } } - details[name='builder-accordion']:not([open]) > div { - display: none; - } - - details[name='builder-accordion'][open] > div { + details[open] > div { display: flex; animation: accordion-open 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; } From facc5d8ccb33634ce16a33806a41e49ba19f0459 Mon Sep 17 00:00:00 2001 From: Darian Date: Mon, 9 Mar 2026 18:23:59 +0200 Subject: [PATCH 02/18] reset steps state after connect/disconnect wallet --- .../components/ToolsWalletAddress.tsx | 12 ++------- frontend/app/hooks/useConnectWallet.tsx | 25 +++++++++++++++++-- frontend/app/stores/toolStore.ts | 3 ++- shared/types/index.ts | 5 +++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/frontend/app/components/redesign/components/ToolsWalletAddress.tsx b/frontend/app/components/redesign/components/ToolsWalletAddress.tsx index f7a775233..37e64ca19 100644 --- a/frontend/app/components/redesign/components/ToolsWalletAddress.tsx +++ b/frontend/app/components/redesign/components/ToolsWalletAddress.tsx @@ -20,7 +20,7 @@ interface Props { export const ToolsWalletAddress = ({ toolName }: Props) => { const snap = useSnapshot(toolState, { sync: true }) - const { connect } = useConnectWallet() + const { connect, disconnect } = useConnectWallet() const uiActions = useUIActions() const [error, setError] = useState() const [isLoading, setIsLoading] = useState(false) @@ -59,7 +59,6 @@ export const ToolsWalletAddress = ({ toolName }: Props) => { const walletAddressInfo = await getWalletAddress(walletAddressUrl) toolActions.setWalletAddressId(walletAddressInfo.id) await connect() - toolActions.setWalletConnected(true) } catch (error) { setError({ fieldErrors: { walletAddress: [(error as Error).message] }, @@ -70,13 +69,6 @@ export const ToolsWalletAddress = ({ toolName }: Props) => { } } - const handleDisconnect = () => { - toolActions.resetProfiles() - toolActions.setWalletConnected(false) - toolActions.setHasRemoteConfigs(false) - uiActions.focusWalletInput() - } - const handleWalletAddressChange = ( e: React.ChangeEvent, ) => { @@ -168,7 +160,7 @@ export const ToolsWalletAddress = ({ toolName }: Props) => {
{snap.isWalletConnected && (