diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 1f3eb359..162f6852 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -17,7 +17,6 @@ model Bounties {
in_progress Boolean? @default(true)
is_joined_bounty Boolean? @default(false)
is_canceled Boolean? @default(false)
- is_banned Boolean? @default(false)
is_multiplayer Boolean?
is_voting Boolean? @default(false)
deadline Int?
@@ -25,6 +24,7 @@ model Bounties {
claims Claims[]
participations ParticipationsBounties[]
issuerUser Users? @relation(fields: [issuer], references: [address])
+ ban Ban[]
@@id([id, chain_id])
}
@@ -36,13 +36,13 @@ model Claims {
description String
url String
issuer String
- is_banned Boolean?
is_accepted Boolean?
bounty_id Int
owner String
bounty Bounties? @relation(fields: [bounty_id, chain_id], references: [id, chain_id])
issuerUser Users? @relation(fields: [issuer], references: [address])
+ ban Ban[]
@@id([id, chain_id])
}
@@ -70,3 +70,15 @@ model Users {
@@id([address])
}
+
+model Ban {
+ id Int @id @default(autoincrement())
+ chain_id Int
+ bounty_id Int?
+ claim_id Int?
+ banned_at DateTime @default(now())
+ banned_by String
+
+ bounty Bounties? @relation(fields: [bounty_id, chain_id], references: [id, chain_id])
+ claim Claims? @relation(fields: [claim_id, chain_id], references: [id, chain_id])
+}
diff --git a/src/app/[netname]/bounty/[id]/page.tsx b/src/app/[netname]/bounty/[id]/page.tsx
index 01f37cbb..9c063c3b 100644
--- a/src/app/[netname]/bounty/[id]/page.tsx
+++ b/src/app/[netname]/bounty/[id]/page.tsx
@@ -7,15 +7,23 @@ import 'react-toastify/dist/ReactToastify.css';
import BountyClaims from '@/components/bounty/BountyClaims';
import BountyInfo from '@/components/bounty/BountyInfo';
import CreateClaim from '@/components/ui/CreateClaim';
+import NavBarMobile from '@/components/global/NavBarMobile';
+import { useScreenSize } from '@/hooks/useScreenSize';
export default function Bounty({ params }: { params: { id: string } }) {
+ const isMobile = useScreenSize();
+
return (
<>
{
}
export default function Layout({ children }: Props) {
- return {children};
+ return children;
}
diff --git a/src/app/[netname]/page.tsx b/src/app/[netname]/page.tsx
index f486c41c..acf62b64 100644
--- a/src/app/[netname]/page.tsx
+++ b/src/app/[netname]/page.tsx
@@ -6,13 +6,17 @@ import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import ContentHome from '@/components/layout/ContentHome';
+import NavBarMobile from '@/components/global/NavBarMobile';
import CreateBounty from '@/components/ui/CreateBounty';
+import { useScreenSize } from '@/hooks/useScreenSize';
export default function Home() {
+ const isMobile = useScreenSize();
+
return (
<>
-
+ {isMobile ? : }
>
);
diff --git a/src/components/bounty/BountyInfo.tsx b/src/components/bounty/BountyInfo.tsx
index b83955c3..9d78d1bb 100644
--- a/src/components/bounty/BountyInfo.tsx
+++ b/src/components/bounty/BountyInfo.tsx
@@ -142,15 +142,15 @@ export default function BountyInfo({ bountyId }: { bountyId: string }) {
toast.error('You are not an admin');
}
}}
- disabled={bounty.data.is_banned || false}
+ disabled={bounty.data.ban.length > 0 || false}
className={cn(
'border border-[#F15E5F] w-fit rounded-md py-2 px-5 mt-5',
- bounty.data.isBanned
+ bounty.data.ban.length > 0
? 'bg-red-400 text-white'
: 'hover:bg-red-400 hover:text-white'
)}
>
- {bounty.data.isBanned ? 'banned' : 'ban'}
+ {bounty.data.ban.length > 0 ? 'banned' : 'ban'}
)}
diff --git a/src/components/bounty/ClaimItem.tsx b/src/components/bounty/ClaimItem.tsx
index 0ce7b9f8..8feb5d37 100644
--- a/src/components/bounty/ClaimItem.tsx
+++ b/src/components/bounty/ClaimItem.tsx
@@ -57,6 +57,7 @@ export default function ClaimItem({
if (!signature) {
throw new Error('Failed to sign message');
}
+
await banClaimMutation.mutateAsync({
id: Number(claimId),
chainId: chain.id,
diff --git a/src/components/global/FormClaim.tsx b/src/components/global/FormClaim.tsx
index 3ad2243d..fc021ac6 100644
--- a/src/components/global/FormClaim.tsx
+++ b/src/components/global/FormClaim.tsx
@@ -35,6 +35,7 @@ export default function FormClaim({
const [status, setStatus] = useState('');
const [file, setFile] = useState(null);
const utils = trpc.useUtils();
+ const [uploading, setUploading] = useState(false);
const account = useAccount();
const writeContract = useWriteContract({});
@@ -53,15 +54,7 @@ export default function FormClaim({
reader.readAsDataURL(file);
}, []);
- const { getRootProps, getInputProps, isDragActive } = useDropzone({
- onDrop,
- maxFiles: 1,
- accept: {
- 'image/png': ['.png'],
- 'image/jpeg': ['.jpg', '.jpeg'],
- 'image/heic': ['.heic'],
- },
- });
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
const compressImage = async (image: File): Promise => {
const options = {
@@ -102,15 +95,19 @@ export default function FormClaim({
useEffect(() => {
const uploadImage = async () => {
if (file) {
+ setUploading(true);
try {
const compressedFile = await compressImage(file);
const cid = await retryUpload(compressedFile);
setImageURI(`${LINK_IPFS}/${cid}`);
} catch (error) {
- toast.error('Failed to upload image: ' + error);
+ console.error('Error uploading file:', error);
+ alert('Trouble uploading file');
}
+ setUploading(false);
}
};
+
uploadImage();
}, [file]);
@@ -208,20 +205,7 @@ export default function FormClaim({
{isDragActive ? (
@@ -237,13 +221,7 @@ export default function FormClaim({
)}
@@ -271,7 +249,7 @@ export default function FormClaim({
account.isDisconnected && 'opacity-50 cursor-not-allowed'
)}
onClick={() => {
- if (name && description && imageURI) {
+ if (name && description && imageURI && !uploading) {
onClose();
createClaimMutations.mutate(BigInt(bountyId));
} else {
diff --git a/src/components/global/GameButton.tsx b/src/components/global/GameButton.tsx
index 968e0768..3b1c0de1 100644
--- a/src/components/global/GameButton.tsx
+++ b/src/components/global/GameButton.tsx
@@ -1,10 +1,10 @@
export default function GameButton() {
return (
- <>
+
- >
+
+ );
+}
+
+export function PlainGameButton() {
+ return (
+
+
+
);
}
diff --git a/src/components/global/NavBarMobile.tsx b/src/components/global/NavBarMobile.tsx
new file mode 100644
index 00000000..572d0c44
--- /dev/null
+++ b/src/components/global/NavBarMobile.tsx
@@ -0,0 +1,70 @@
+import FormBounty from '@/components/global/FormBounty';
+import FormClaim from '@/components/global/FormClaim';
+import GameButton, { PlainGameButton } from '@/components/global/GameButton';
+import React, { useState } from 'react';
+import { toast } from 'react-toastify';
+import { useAccount } from 'wagmi';
+
+export default function NavBarMobile({
+ type,
+ bountyId,
+}: {
+ type: 'claim' | 'bounty';
+ bountyId?: string;
+}) {
+ const [showForm, setShowForm] = useState(false);
+ const account = useAccount();
+ return (
+ <>
+
+
+ {type === 'bounty' ? (
+ setShowForm(false)} />
+ ) : (
+ bountyId && (
+ setShowForm(false)}
+ />
+ )
+ )}
+ >
+ );
+}
diff --git a/src/components/global/Wrapper.tsx b/src/components/global/Wrapper.tsx
deleted file mode 100644
index 47bc6833..00000000
--- a/src/components/global/Wrapper.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-'use client';
-
-import React, { useEffect } from 'react';
-
-import '@/styles/globals.css';
-import '@/styles/colors.css';
-
-import { useGetChain } from '@/hooks/useGetChain';
-import { useAccount, useSwitchChain } from 'wagmi';
-
-export default function Wrapper({ children }: { children: React.ReactNode }) {
- const chain = useGetChain();
- const account = useAccount();
- const switchChain = useSwitchChain();
-
- useEffect(() => {
- if (account.isConnected) {
- if (chain.id !== account.chainId) {
- switchChain.switchChain({ chainId: chain.id });
- }
- }
- }, [account, chain, switchChain]);
-
- return <>{children}>;
-}
diff --git a/src/components/ui/CreateBounty.tsx b/src/components/ui/CreateBounty.tsx
index 33d5a7ea..65b95af7 100644
--- a/src/components/ui/CreateBounty.tsx
+++ b/src/components/ui/CreateBounty.tsx
@@ -13,7 +13,7 @@ export default function CreateBounty() {
{!showForm && (
{
if (account.isConnected) {
setShowForm(true);
diff --git a/src/components/ui/CreateClaim.tsx b/src/components/ui/CreateClaim.tsx
index 6986f71b..5e9cda86 100644
--- a/src/components/ui/CreateClaim.tsx
+++ b/src/components/ui/CreateClaim.tsx
@@ -25,7 +25,7 @@ export default function CreateClaim({ bountyId }: { bountyId: string }) {
{!showForm && (
{
if (account.isConnected) {
setShowForm(true);
diff --git a/src/hooks/useScreenSize.ts b/src/hooks/useScreenSize.ts
new file mode 100644
index 00000000..5dc76af4
--- /dev/null
+++ b/src/hooks/useScreenSize.ts
@@ -0,0 +1,18 @@
+import { useState, useEffect } from 'react';
+
+export const useScreenSize = () => {
+ const [isMobile, setIsMobile] = useState(false);
+
+ useEffect(() => {
+ const checkScreenSize = () => {
+ setIsMobile(window.innerWidth < 768);
+ };
+ checkScreenSize();
+
+ window.addEventListener('resize', checkScreenSize);
+
+ return () => window.removeEventListener('resize', checkScreenSize);
+ }, []);
+
+ return isMobile;
+};
diff --git a/src/trpc/routers/_app.ts b/src/trpc/routers/_app.ts
index 3e934050..b4d7f1b7 100644
--- a/src/trpc/routers/_app.ts
+++ b/src/trpc/routers/_app.ts
@@ -41,6 +41,7 @@ export const appRouter = createTRPCRouter({
},
},
include: {
+ ban: true,
claims: {
take: 1,
},
@@ -59,7 +60,7 @@ export const appRouter = createTRPCRouter({
hasClaims: bounty.claims.length > 0,
inProgress: bounty.in_progress,
isMultiplayer: bounty.is_multiplayer,
- isBanned: bounty.is_banned,
+ isBanned: bounty.ban.length > 0,
isCanceled: bounty.is_canceled,
};
}),
@@ -77,7 +78,9 @@ export const appRouter = createTRPCRouter({
const items = await prisma.bounties.findMany({
where: {
chain_id: input.chainId,
- is_banned: false,
+ ban: {
+ none: {},
+ },
...(input.status === 'open'
? {
in_progress: true,
@@ -147,7 +150,9 @@ export const appRouter = createTRPCRouter({
where: {
bounty_id: input.bountyId,
chain_id: input.chainId,
- is_banned: false,
+ ban: {
+ none: {},
+ },
...(input.cursor ? { id: { lt: input.cursor } } : {}),
},
orderBy: { id: 'desc' },
@@ -183,7 +188,9 @@ export const appRouter = createTRPCRouter({
id: input.claimId,
chain_id: input.chainId,
},
- is_banned: false,
+ ban: {
+ none: {},
+ },
},
select: {
id: true,
@@ -209,7 +216,9 @@ export const appRouter = createTRPCRouter({
where: {
issuer: input.address,
chain_id: input.chainId,
- is_banned: false,
+ ban: {
+ none: {},
+ },
is_canceled: false,
},
select: {
@@ -252,7 +261,9 @@ export const appRouter = createTRPCRouter({
where: {
issuer: input.address,
chain_id: input.chainId,
- is_banned: false,
+ ban: {
+ none: {},
+ },
},
select: {
id: true,
@@ -462,15 +473,11 @@ export const appRouter = createTRPCRouter({
});
}
- await prisma.bounties.update({
- where: {
- id_chain_id: {
- id: input.id,
- chain_id: input.chainId,
- },
- },
+ await prisma.ban.create({
data: {
- is_banned: true,
+ chain_id: input.chainId,
+ bounty_id: input.id,
+ banned_by: input.address.toLowerCase(),
},
});
}),
@@ -523,15 +530,11 @@ export const appRouter = createTRPCRouter({
});
}
- await prisma.claims.update({
- where: {
- id_chain_id: {
- id: input.id,
- chain_id: input.chainId,
- },
- },
+ await prisma.ban.create({
data: {
- is_banned: true,
+ chain_id: input.chainId,
+ banned_by: input.address.toLowerCase(),
+ claim_id: input.id,
},
});
}),