Inga/manalink bug fixes (#653)
* fixed manalinks bug of claiming own manalink, and also rerouting to home upon claiming if not logged in * no more multiple hardcoded manalink messages
This commit is contained in:
parent
eed7990c3c
commit
7d24a3e4a2
|
@ -27,6 +27,7 @@ Adapted from https://firebase.google.com/docs/functions/get-started
|
||||||
|
|
||||||
1. `$ brew install java`
|
1. `$ brew install java`
|
||||||
2. `$ sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk`
|
2. `$ sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk`
|
||||||
|
|
||||||
2. `$ gcloud auth login` to authenticate the CLI tools to Google Cloud
|
2. `$ gcloud auth login` to authenticate the CLI tools to Google Cloud
|
||||||
3. `$ gcloud config set project <project-id>` to choose the project (`$ gcloud projects list` to see options)
|
3. `$ gcloud config set project <project-id>` to choose the project (`$ gcloud projects list` to see options)
|
||||||
4. `$ mkdir firestore_export` to create a folder to store the exported database
|
4. `$ mkdir firestore_export` to create a folder to store the exported database
|
||||||
|
@ -53,7 +54,10 @@ Adapted from https://firebase.google.com/docs/functions/get-started
|
||||||
|
|
||||||
## Deploying
|
## Deploying
|
||||||
|
|
||||||
0. `$ firebase use prod` to switch to prod
|
0. After merging, you need to manually deploy to backend:
|
||||||
|
1. `git checkout main`
|
||||||
|
1. `git pull origin main`
|
||||||
|
1. `$ firebase use prod` to switch to prod
|
||||||
1. `$ firebase deploy --only functions` to push your changes live!
|
1. `$ firebase deploy --only functions` to push your changes live!
|
||||||
(Future TODO: auto-deploy functions on Git push)
|
(Future TODO: auto-deploy functions on Git push)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@ export const claimmanalink = newEndpoint({}, async (req, auth) => {
|
||||||
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
|
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
|
||||||
throw new APIError(500, 'Invalid amount')
|
throw new APIError(500, 'Invalid amount')
|
||||||
|
|
||||||
|
if (auth.uid === fromId)
|
||||||
|
throw new APIError(400, `You can't claim your own manalink`)
|
||||||
|
|
||||||
const fromDoc = firestore.doc(`users/${fromId}`)
|
const fromDoc = firestore.doc(`users/${fromId}`)
|
||||||
const fromSnap = await transaction.get(fromDoc)
|
const fromSnap = await transaction.get(fromDoc)
|
||||||
if (!fromSnap.exists) {
|
if (!fromSnap.exists) {
|
||||||
|
|
|
@ -2,12 +2,13 @@ import { ReactNode } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
export function Button(props: {
|
export function Button(props: {
|
||||||
children: ReactNode
|
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
|
children?: ReactNode
|
||||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
||||||
color?: 'green' | 'red' | 'blue' | 'indigo' | 'yellow' | 'gray'
|
color?: 'green' | 'red' | 'blue' | 'indigo' | 'yellow' | 'gray'
|
||||||
type?: 'button' | 'reset' | 'submit'
|
type?: 'button' | 'reset' | 'submit'
|
||||||
|
disabled?: boolean
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
|
@ -16,6 +17,7 @@ export function Button(props: {
|
||||||
size = 'md',
|
size = 'md',
|
||||||
color = 'indigo',
|
color = 'indigo',
|
||||||
type = 'button',
|
type = 'button',
|
||||||
|
disabled = false,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const sizeClasses = {
|
const sizeClasses = {
|
||||||
|
@ -30,7 +32,7 @@ export function Button(props: {
|
||||||
<button
|
<button
|
||||||
type={type}
|
type={type}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'font-md items-center justify-center rounded-md border border-transparent shadow-sm hover:transition-colors',
|
'font-md items-center justify-center rounded-md border border-transparent shadow-sm hover:transition-colors disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
sizeClasses,
|
sizeClasses,
|
||||||
color === 'green' && 'btn-primary text-white',
|
color === 'green' && 'btn-primary text-white',
|
||||||
color === 'red' && 'bg-red-400 text-white hover:bg-red-500',
|
color === 'red' && 'bg-red-400 text-white hover:bg-red-500',
|
||||||
|
@ -40,6 +42,7 @@ export function Button(props: {
|
||||||
color === 'gray' && 'bg-gray-200 text-gray-700 hover:bg-gray-300',
|
color === 'gray' && 'bg-gray-200 text-gray-700 hover:bg-gray-300',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
disabled={disabled}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { formatMoney } from 'common/util/format'
|
||||||
import { fromNow } from 'web/lib/util/time'
|
import { fromNow } from 'web/lib/util/time'
|
||||||
import { Col } from 'web/components/layout/col'
|
import { Col } from 'web/components/layout/col'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
import { User } from 'web/lib/firebase/users'
|
||||||
|
import { Button } from './button'
|
||||||
|
|
||||||
export type ManalinkInfo = {
|
export type ManalinkInfo = {
|
||||||
expiresTime: number | null
|
expiresTime: number | null
|
||||||
|
@ -13,13 +15,13 @@ export type ManalinkInfo = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ManalinkCard(props: {
|
export function ManalinkCard(props: {
|
||||||
|
user: User | null | undefined
|
||||||
className?: string
|
className?: string
|
||||||
info: ManalinkInfo
|
info: ManalinkInfo
|
||||||
defaultMessage: string
|
|
||||||
isClaiming: boolean
|
isClaiming: boolean
|
||||||
onClaim?: () => void
|
onClaim?: () => void
|
||||||
}) {
|
}) {
|
||||||
const { className, defaultMessage, isClaiming, info, onClaim } = props
|
const { user, className, isClaiming, info, onClaim } = props
|
||||||
const { expiresTime, maxUses, uses, amount, message } = info
|
const { expiresTime, maxUses, uses, amount, message } = info
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -52,16 +54,13 @@ export function ManalinkCard(props: {
|
||||||
<div className="mb-1 text-xl text-indigo-500">
|
<div className="mb-1 text-xl text-indigo-500">
|
||||||
{formatMoney(amount)}
|
{formatMoney(amount)}
|
||||||
</div>
|
</div>
|
||||||
<div>{message || defaultMessage}</div>
|
<div>{message}</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<div className="ml-auto">
|
<div className="ml-auto">
|
||||||
<button
|
<Button onClick={onClaim} disabled={isClaiming}>
|
||||||
className={clsx('btn', isClaiming ? 'loading disabled' : '')}
|
{user ? 'Claim' : 'Login'}
|
||||||
onClick={onClaim}
|
</Button>
|
||||||
>
|
|
||||||
{isClaiming ? '' : 'Claim'}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,9 +70,8 @@ export function ManalinkCard(props: {
|
||||||
export function ManalinkCardPreview(props: {
|
export function ManalinkCardPreview(props: {
|
||||||
className?: string
|
className?: string
|
||||||
info: ManalinkInfo
|
info: ManalinkInfo
|
||||||
defaultMessage: string
|
|
||||||
}) {
|
}) {
|
||||||
const { className, defaultMessage, info } = props
|
const { className, info } = props
|
||||||
const { expiresTime, maxUses, uses, amount, message } = info
|
const { expiresTime, maxUses, uses, amount, message } = info
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -102,7 +100,7 @@ export function ManalinkCardPreview(props: {
|
||||||
<Row className="rounded-b-lg bg-white p-2">
|
<Row className="rounded-b-lg bg-white p-2">
|
||||||
<Col className="text-md">
|
<Col className="text-md">
|
||||||
<div className="mb-1 text-indigo-500">{formatMoney(amount)}</div>
|
<div className="mb-1 text-indigo-500">{formatMoney(amount)}</div>
|
||||||
<div className="text-xs">{message || defaultMessage}</div>
|
<div className="text-xs">{message}</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -66,12 +66,14 @@ function CreateManalinkForm(props: {
|
||||||
const defaultExpire = 'week'
|
const defaultExpire = 'week'
|
||||||
const [expiresIn, setExpiresIn] = useState(defaultExpire)
|
const [expiresIn, setExpiresIn] = useState(defaultExpire)
|
||||||
|
|
||||||
|
const defaultMessage = 'from ' + user.name
|
||||||
|
|
||||||
const [newManalink, setNewManalink] = useState<ManalinkInfo>({
|
const [newManalink, setNewManalink] = useState<ManalinkInfo>({
|
||||||
expiresTime: dayjs().add(1, defaultExpire).valueOf(),
|
expiresTime: dayjs().add(1, defaultExpire).valueOf(),
|
||||||
amount: 100,
|
amount: 100,
|
||||||
maxUses: 1,
|
maxUses: 1,
|
||||||
uses: 0,
|
uses: 0,
|
||||||
message: '',
|
message: defaultMessage,
|
||||||
})
|
})
|
||||||
|
|
||||||
const EXPIRE_OPTIONS = {
|
const EXPIRE_OPTIONS = {
|
||||||
|
@ -161,7 +163,7 @@ function CreateManalinkForm(props: {
|
||||||
<div className="form-control w-full">
|
<div className="form-control w-full">
|
||||||
<label className="label">Message</label>
|
<label className="label">Message</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder={`From ${user.name}`}
|
placeholder={defaultMessage}
|
||||||
className="input input-bordered resize-none"
|
className="input input-bordered resize-none"
|
||||||
autoFocus
|
autoFocus
|
||||||
value={newManalink.message}
|
value={newManalink.message}
|
||||||
|
@ -189,11 +191,7 @@ function CreateManalinkForm(props: {
|
||||||
{finishedCreating && (
|
{finishedCreating && (
|
||||||
<>
|
<>
|
||||||
<Title className="!my-0" text="Manalink Created!" />
|
<Title className="!my-0" text="Manalink Created!" />
|
||||||
<ManalinkCardPreview
|
<ManalinkCardPreview className="my-4" info={newManalink} />
|
||||||
className="my-4"
|
|
||||||
defaultMessage={`From ${user.name}`}
|
|
||||||
info={newManalink}
|
|
||||||
/>
|
|
||||||
<Row
|
<Row
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded border bg-gray-50 py-2 px-3 text-sm text-gray-500 transition-colors duration-700',
|
'rounded border bg-gray-50 py-2 px-3 text-sm text-gray-500 transition-colors duration-700',
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { claimManalink } from 'web/lib/firebase/api'
|
||||||
import { useManalink } from 'web/lib/firebase/manalinks'
|
import { useManalink } from 'web/lib/firebase/manalinks'
|
||||||
import { ManalinkCard } from 'web/components/manalink-card'
|
import { ManalinkCard } from 'web/components/manalink-card'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { useUserById } from 'web/hooks/use-user'
|
|
||||||
import { firebaseLogin } from 'web/lib/firebase/users'
|
import { firebaseLogin } from 'web/lib/firebase/users'
|
||||||
|
|
||||||
export default function ClaimPage() {
|
export default function ClaimPage() {
|
||||||
|
@ -17,7 +16,6 @@ export default function ClaimPage() {
|
||||||
const [claiming, setClaiming] = useState(false)
|
const [claiming, setClaiming] = useState(false)
|
||||||
const [error, setError] = useState<string | undefined>(undefined)
|
const [error, setError] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
const fromUser = useUserById(manalink?.fromId)
|
|
||||||
if (!manalink) {
|
if (!manalink) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
@ -33,7 +31,7 @@ export default function ClaimPage() {
|
||||||
<div className="mx-auto max-w-xl">
|
<div className="mx-auto max-w-xl">
|
||||||
<Title text={`Claim M$${manalink.amount} mana`} />
|
<Title text={`Claim M$${manalink.amount} mana`} />
|
||||||
<ManalinkCard
|
<ManalinkCard
|
||||||
defaultMessage={fromUser?.name || 'Enjoy this mana!'}
|
user={user}
|
||||||
info={info}
|
info={info}
|
||||||
isClaiming={claiming}
|
isClaiming={claiming}
|
||||||
onClaim={async () => {
|
onClaim={async () => {
|
||||||
|
@ -41,6 +39,11 @@ export default function ClaimPage() {
|
||||||
try {
|
try {
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
await firebaseLogin()
|
await firebaseLogin()
|
||||||
|
setClaiming(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (user?.id == manalink.fromId) {
|
||||||
|
throw new Error("You can't claim your own manalink.")
|
||||||
}
|
}
|
||||||
await claimManalink({ slug: manalink.slug })
|
await claimManalink({ slug: manalink.slug })
|
||||||
user && router.push(`/${user.username}?claimed-mana=yes`)
|
user && router.push(`/${user.username}?claimed-mana=yes`)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user