a tool for shared writing and social publishing

added a manage pro sunscription to account and publication settings

+149 -65
+33 -2
app/(home-pages)/home/Actions/AccountSettings.tsx
··· 11 11 import { useState } from "react"; 12 12 import { ThemeSetterContent } from "components/ThemeManager/ThemeSetter"; 13 13 import { useIsMobile } from "src/hooks/isMobile"; 14 + import { ManageProSubscription } from "app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription"; 15 + import { Modal } from "components/Modal"; 16 + import { UpgradeContent } from "app/lish/[did]/[publication]/UpgradeModal"; 14 17 15 18 export const AccountSettings = (props: { entityID: string }) => { 16 - let [state, setState] = useState<"menu" | "general" | "theme">("menu"); 19 + let [state, setState] = useState< 20 + "menu" | "general" | "theme" | "manage-subscription" 21 + >("menu"); 17 22 let isMobile = useIsMobile(); 18 23 19 24 return ( ··· 32 37 entityID={props.entityID} 33 38 backToMenu={() => setState("menu")} 34 39 /> 40 + ) : state === "manage-subscription" ? ( 41 + <ManageProSubscription backToMenu={() => setState("menu")} /> 35 42 ) : ( 36 43 <SettingsMenu state={state} setState={setState} /> 37 44 )} ··· 40 47 }; 41 48 42 49 const SettingsMenu = (props: { 43 - state: "menu" | "general" | "theme"; 50 + state: "menu" | "general" | "theme" | "manage-subscription"; 44 51 setState: (s: typeof props.state) => void; 45 52 }) => { 46 53 let menuItemClassName = 47 54 "menuItem -mx-[8px] text-left flex items-center justify-between hover:no-underline!"; 55 + 56 + let isPro = true; 48 57 49 58 return ( 50 59 <div className="flex flex-col gap-0.5"> ··· 67 76 Account Theme 68 77 <ArrowRightTiny /> 69 78 </button> 79 + {!isPro ? ( 80 + <Modal 81 + trigger={ 82 + <div 83 + className={`${menuItemClassName} bg-[var(--accent-light)]! border border-transparent hover:border-accent-contrast`} 84 + > 85 + Get Leaflet Pro 86 + <ArrowRightTiny />{" "} 87 + </div> 88 + } 89 + > 90 + <UpgradeContent /> 91 + </Modal> 92 + ) : ( 93 + <button 94 + className={`${menuItemClassName} bg-[var(--accent-light)]! border border-transparent hover:border-accent-contrast`} 95 + type="button" 96 + onClick={() => props.setState("manage-subscription")} 97 + > 98 + Manage Pro Subscription <ArrowRightTiny />{" "} 99 + </button> 100 + )} 70 101 </div> 71 102 ); 72 103 };
-24
app/lish/[did]/[publication]/dashboard/Actions.tsx
··· 22 22 23 23 <PublicationShareButton /> 24 24 <PublicationSettingsButton publication={props.publication} /> 25 - <DesktopUpgrade /> 26 25 </> 27 26 ); 28 27 }; ··· 98 97 /> 99 98 ); 100 99 }; 101 - 102 - const DesktopUpgrade = () => { 103 - return ( 104 - <div 105 - style={{ backgroundColor: "var(--accent-light)" }} 106 - className=" rounded-md mt-2 pt-2 pb-3 px-3 sm:block hidden" 107 - > 108 - <h4 className="text-accent-contrast text-sm">Get Leaflet Pro</h4> 109 - <div className="text-xs text-secondary mb-2"> 110 - <strong>Analytics!</strong> Emails and membership soon. 111 - </div> 112 - <UpgradeModal 113 - asChild 114 - trigger={ 115 - <ButtonSecondary fullWidth compact className="text-sm!"> 116 - Learn more 117 - </ButtonSecondary> 118 - } 119 - /> 120 - <ButtonTertiary className="mx-auto text-sm">Dismiss</ButtonTertiary> 121 - </div> 122 - ); 123 - };
+14 -14
app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx
··· 11 11 ComboboxResult, 12 12 useComboboxState, 13 13 } from "components/Combobox"; 14 - import { Input } from "components/Input"; 15 14 16 15 type referrorType = { iconSrc: string; name: string; viewCount: string }; 17 16 let refferors = [ ··· 104 103 posts.filter((post) => 105 104 post.toLowerCase().includes(searchValue.toLowerCase()), 106 105 ), 107 - [searchValue], 106 + [searchValue, posts], 108 107 ); 109 108 110 109 let filteredPostsWithClear = ["All Posts", ...(filteredPosts || [])]; ··· 132 131 return ( 133 132 <> 134 133 <ComboboxResult 134 + key="all posts" 135 135 result={post} 136 136 onSelect={() => { 137 137 props.setSelectedPost(undefined); ··· 147 147 </> 148 148 ); 149 149 return ( 150 - <> 151 - <ComboboxResult 152 - result={post} 153 - onSelect={() => { 154 - props.setSelectedPost(post); 155 - }} 156 - highlighted={highlighted} 157 - setHighlighted={setHighlighted} 158 - > 159 - {post} 160 - </ComboboxResult> 161 - </> 150 + <ComboboxResult 151 + key={post} 152 + result={post} 153 + onSelect={() => { 154 + props.setSelectedPost(post); 155 + }} 156 + highlighted={highlighted} 157 + setHighlighted={setHighlighted} 158 + > 159 + {post} 160 + </ComboboxResult> 162 161 ); 163 162 })} 164 163 </Combobox> ··· 261 260 return ( 262 261 <> 263 262 <button 263 + key={ref.name} 264 264 className={`w-full flex justify-between gap-4 px-1 items-center text-right rounded-md ${selected ? "text-accent-contrast bg-[var(--accent-light)]" : ""}`} 265 265 onClick={() => { 266 266 props.setSelectedReferror(ref);
+51
app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription.tsx
··· 1 + import { useState } from "react"; 2 + import { ButtonPrimary } from "components/Buttons"; 3 + import { PubSettingsHeader } from "./PublicationSettings"; 4 + 5 + export const ManageProSubscription = (props: { backToMenu: () => void }) => { 6 + const [state, setState] = useState<"manage" | "confirm" | "success">( 7 + "manage", 8 + ); 9 + 10 + return ( 11 + <div> 12 + <PubSettingsHeader backToMenuAction={props.backToMenu}> 13 + Manage Subscription 14 + </PubSettingsHeader> 15 + <div className="text-secondary text-center flex flex-col justify-center gap-2 py-2"> 16 + {state === "manage" && ( 17 + <> 18 + <div> 19 + You have a <br /> 20 + Pro monthly subscription 21 + <div className="text-lg font-bold text-primary">$12/mo </div> 22 + Renews on the 12th 23 + </div> 24 + <ButtonPrimary 25 + className="mx-auto" 26 + compact 27 + onClick={() => setState("confirm")} 28 + > 29 + Cancel Subscription 30 + </ButtonPrimary> 31 + </> 32 + )} 33 + {state === "confirm" && ( 34 + <> 35 + <div>Are you sure you'd like to cancel your subscription?</div> 36 + <ButtonPrimary 37 + className="mx-auto" 38 + compact 39 + onClick={() => setState("success")} 40 + > 41 + Yes, Cancel it 42 + </ButtonPrimary> 43 + </> 44 + )} 45 + {state === "success" && ( 46 + <div>Your subscription has been successfully cancelled!</div> 47 + )} 48 + </div> 49 + </div> 50 + ); 51 + };
-1
app/lish/[did]/[publication]/dashboard/settings/PostOptions.tsx
··· 65 65 loading={props.loading} 66 66 setLoadingAction={props.setLoading} 67 67 backToMenuAction={props.backToMenu} 68 - state={"post-options"} 69 68 > 70 69 Post Options 71 70 </PubSettingsHeader>
+51 -24
app/lish/[did]/[publication]/dashboard/settings/PublicationSettings.tsx
··· 13 13 import { DotLoader } from "components/utils/DotLoader"; 14 14 import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; 15 15 import { PostOptions } from "./PostOptions"; 16 + import { UpgradeContent } from "../../UpgradeModal"; 17 + import { Modal } from "components/Modal"; 18 + import { ManageProSubscription } from "./ManageProSubscription"; 16 19 17 - type menuState = "menu" | "general" | "theme" | "post-options"; 20 + type menuState = 21 + | "menu" 22 + | "pub-settings" 23 + | "theme" 24 + | "post-settings" 25 + | "manage-subscription"; 18 26 19 27 export function PublicationSettingsButton(props: { publication: string }) { 20 28 let isMobile = useIsMobile(); ··· 37 45 /> 38 46 } 39 47 > 40 - {state === "general" ? ( 48 + {state === "pub-settings" ? ( 41 49 <EditPubForm 42 50 backToMenuAction={() => setState("menu")} 43 51 loading={loading} ··· 49 57 loading={loading} 50 58 setLoading={setLoading} 51 59 /> 52 - ) : state === "post-options" ? ( 60 + ) : state === "post-settings" ? ( 53 61 <PostOptions 54 62 backToMenu={() => setState("menu")} 55 63 loading={loading} 56 64 setLoading={setLoading} 57 65 /> 66 + ) : state === "manage-subscription" ? ( 67 + <ManageProSubscription backToMenu={() => setState("menu")} /> 58 68 ) : ( 59 69 <PubSettingsMenu 60 70 state={state} ··· 75 85 }) => { 76 86 let menuItemClassName = 77 87 "menuItem -mx-[8px] text-left flex items-center justify-between hover:no-underline!"; 88 + let isPro = true; 78 89 79 90 return ( 80 91 <div className="flex flex-col gap-0.5"> 81 - <PubSettingsHeader 82 - loading={props.loading} 83 - setLoadingAction={props.setLoading} 84 - state={"menu"} 85 - > 86 - Settings 87 - </PubSettingsHeader> 92 + <PubSettingsHeader>Settings</PubSettingsHeader> 88 93 <button 89 94 className={menuItemClassName} 90 95 type="button" 91 96 onClick={() => { 92 - props.setState("general"); 97 + props.setState("pub-settings"); 93 98 }} 94 99 > 95 - General Settings 100 + Publiction Settings 96 101 <ArrowRightTiny /> 97 102 </button> 98 103 <button 99 104 className={menuItemClassName} 100 105 type="button" 101 - onClick={() => props.setState("theme")} 106 + onClick={() => props.setState("post-settings")} 102 107 > 103 - Theme and Layout 108 + Post Settings 104 109 <ArrowRightTiny /> 105 110 </button> 106 111 <button 107 112 className={menuItemClassName} 108 113 type="button" 109 - onClick={() => props.setState("post-options")} 114 + onClick={() => props.setState("theme")} 110 115 > 111 - Post Options 116 + Theme and Layout 112 117 <ArrowRightTiny /> 113 118 </button> 119 + {!isPro ? ( 120 + <Modal 121 + trigger={ 122 + <div 123 + className={`${menuItemClassName} bg-[var(--accent-light)]! border border-transparent hover:border-accent-contrast`} 124 + > 125 + Get Leaflet Pro 126 + <ArrowRightTiny />{" "} 127 + </div> 128 + } 129 + > 130 + <UpgradeContent /> 131 + </Modal> 132 + ) : ( 133 + <button 134 + className={`${menuItemClassName} bg-[var(--accent-light)]! border border-transparent hover:border-accent-contrast`} 135 + type="button" 136 + onClick={() => props.setState("manage-subscription")} 137 + > 138 + Manage Pro Subscription <ArrowRightTiny />{" "} 139 + </button> 140 + )} 114 141 </div> 115 142 ); 116 143 }; 117 144 118 145 export const PubSettingsHeader = (props: { 119 - state: menuState; 120 146 backToMenuAction?: () => void; 121 - loading: boolean; 122 - setLoadingAction: (l: boolean) => void; 147 + loading?: boolean; 148 + setLoadingAction?: (l: boolean) => void; 123 149 children: React.ReactNode; 124 150 }) => { 125 151 return ( 126 152 <div className="flex justify-between font-bold text-secondary bg-border-light -mx-3 -mt-2 px-3 py-2 mb-1"> 127 153 {props.children} 128 - {props.state !== "menu" && ( 154 + {props.backToMenuAction && ( 129 155 <div className="flex gap-2"> 130 156 <button 131 157 type="button" ··· 135 161 > 136 162 <GoBackSmall className="text-accent-contrast" /> 137 163 </button> 138 - 139 - <ButtonPrimary compact type="submit"> 140 - {props.loading ? <DotLoader /> : "Update"} 141 - </ButtonPrimary> 164 + {props.setLoadingAction && ( 165 + <ButtonPrimary compact type="submit"> 166 + {props.loading ? <DotLoader /> : "Update"} 167 + </ButtonPrimary> 168 + )} 142 169 </div> 143 170 )} 144 171 </div>