a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add login popover for subscribe

+85 -34
+28 -1
app/lish/Subscribe.tsx
··· 1 1 "use client"; 2 2 import { ButtonPrimary } from "components/Buttons"; 3 - import { useActionState, useState } from "react"; 3 + import { useActionState, useEffect, useState } from "react"; 4 4 import { Input } from "components/Input"; 5 5 import { useIdentityData } from "components/IdentityProvider"; 6 6 import { ··· 21 21 import { DotLoader } from "components/utils/DotLoader"; 22 22 import { addFeed } from "./addFeed"; 23 23 import { useSearchParams } from "next/navigation"; 24 + import LoginForm from "app/login/LoginForm"; 24 25 25 26 type State = 26 27 | { state: "email" } ··· 273 274 pub_uri: string; 274 275 setSuccessModalOpen: (open: boolean) => void; 275 276 }) => { 277 + let { identity } = useIdentityData(); 276 278 let [, subscribe, subscribePending] = useActionState(async () => { 277 279 let result = await subscribeToPublication( 278 280 props.pub_uri, ··· 282 284 props.setSuccessModalOpen(true); 283 285 } 284 286 }, null); 287 + let [isClient, setIsClient] = useState(false); 288 + useEffect(() => { 289 + setIsClient(true); 290 + }, []); 291 + 292 + if (!identity?.atp_did) { 293 + return ( 294 + <Popover 295 + asChild 296 + trigger={ 297 + <ButtonPrimary className="place-self-center"> 298 + <BlueskyTiny /> Subscribe with Bluesky{" "} 299 + </ButtonPrimary> 300 + } 301 + > 302 + {isClient && ( 303 + <LoginForm 304 + noEmail 305 + redirectRoute={window?.location.href + "?refreshAuth"} 306 + action={{ action: "subscribe", publication: props.pub_uri }} 307 + /> 308 + )} 309 + </Popover> 310 + ); 311 + } 285 312 286 313 return ( 287 314 <>
+57 -33
app/login/LoginForm.tsx
··· 4 4 requestAuthEmailToken, 5 5 } from "actions/emailAuth"; 6 6 import { loginWithEmailToken } from "actions/login"; 7 + import { ActionAfterSignIn } from "app/api/oauth/[route]/afterSignInActions"; 7 8 import { getHomeDocs } from "app/home/storage"; 8 9 import { ButtonPrimary } from "components/Buttons"; 9 10 import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; ··· 13 14 import React, { useState } from "react"; 14 15 import { mutate } from "swr"; 15 16 16 - export default function LoginForm() { 17 + export default function LoginForm(props: { 18 + noEmail?: boolean; 19 + redirectRoute?: string; 20 + action?: ActionAfterSignIn; 21 + }) { 17 22 type FormState = 18 23 | { 19 24 stage: "email"; ··· 120 125 </div> 121 126 </div> 122 127 123 - <BlueskyLogin /> 128 + <BlueskyLogin {...props} /> 124 129 125 - <div className="flex gap-2 text-border italic w-full items-center"> 126 - <hr className="border-border-light w-full" /> 127 - <div>or</div> 128 - <hr className="border-border-light w-full" /> 129 - </div> 130 - <form 131 - onSubmit={handleSubmitEmail} 132 - className="flex flex-col gap-2 relative" 133 - > 134 - <Input 135 - type="email" 136 - placeholder="email@example.com" 137 - value={formState.email} 138 - className="input-with-border p-7" 139 - onChange={(e) => 140 - setFormState({ 141 - ...formState, 142 - email: e.target.value, 143 - }) 144 - } 145 - required 146 - /> 130 + {props.noEmail ? null : ( 131 + <> 132 + <div className="flex gap-2 text-border italic w-full items-center"> 133 + <hr className="border-border-light w-full" /> 134 + <div>or</div> 135 + <hr className="border-border-light w-full" /> 136 + </div> 137 + <form 138 + onSubmit={handleSubmitEmail} 139 + className="flex flex-col gap-2 relative" 140 + > 141 + <Input 142 + type="email" 143 + placeholder="email@example.com" 144 + value={formState.email} 145 + className="input-with-border p-7" 146 + onChange={(e) => 147 + setFormState({ 148 + ...formState, 149 + email: e.target.value, 150 + }) 151 + } 152 + required 153 + /> 147 154 148 - <ButtonPrimary 149 - type="submit" 150 - className="place-self-end !px-[2px] absolute right-1 bottom-1" 151 - > 152 - <ArrowRightTiny />{" "} 153 - </ButtonPrimary> 154 - </form> 155 + <ButtonPrimary 156 + type="submit" 157 + className="place-self-end !px-[2px] absolute right-1 bottom-1" 158 + > 159 + <ArrowRightTiny />{" "} 160 + </ButtonPrimary> 161 + </form> 162 + </> 163 + )} 155 164 </div> 156 165 ); 157 166 } 158 167 159 - export function BlueskyLogin() { 168 + export function BlueskyLogin(props: { 169 + redirectRoute?: string; 170 + action?: ActionAfterSignIn; 171 + }) { 160 172 const [signingWithHandle, setSigningWithHandle] = useState(false); 161 173 const [handle, setHandle] = useState(""); 162 174 163 175 return ( 164 - <form action="/api/oauth/login?redirect_url=/" method="GET"> 176 + <form action={`/api/oauth/login`} method="GET"> 177 + <input 178 + type="hidden" 179 + name="redirect_url" 180 + value={props.redirectRoute || "/"} 181 + /> 182 + {props.action && ( 183 + <input 184 + type="hidden" 185 + name="action" 186 + value={JSON.stringify(props.action)} 187 + /> 188 + )} 165 189 {signingWithHandle ? ( 166 190 <div className="w-full flex flex-col gap-2"> 167 191 <Input