diff --git a/DevoteApp/.env.local b/DevoteApp/.env.local index 817faa1..52e8902 100644 --- a/DevoteApp/.env.local +++ b/DevoteApp/.env.local @@ -1,4 +1,15 @@ NEXT_PUBLIC_SECRET_TOKEN=devote_superuser_secret_2024 -NEXT_PUBLIC_API_URL=http://localhost:3000/api -DATABASE_URL=postgresql://user:password@localhost:5432/devotedb -STARKNET_RPC_URL=http://localhost:5050 \ No newline at end of file + +STARKNET_RPC_URL=http://localhost:5050 + +MONGO_URI=mongodb://localhost:27017/devote +# Email Configuration (for user notifications) +EMAIL_SMTP_HOST=smtp.gmail.com +EMAIL_SMTP_PORT=587 +EMAIL_SMTP_SECURE=false +EMAIL_USER=your-email@gmail.com +EMAIL_PASS=your-app-password +# Frontend URL +FRONTEND_URL=http://localhost:3000 + +VERCEL_BLOB_READ_WRITE_TOKEN=your_vercel_blob_rw_token_here diff --git a/DevoteApp/app/admin/create-proposal/page.tsx b/DevoteApp/app/admin/create-proposal/page.tsx new file mode 100644 index 0000000..05cc921 --- /dev/null +++ b/DevoteApp/app/admin/create-proposal/page.tsx @@ -0,0 +1,7 @@ +const handleSubmit= async (e:React.FormEvent)=>{ + e.preventDefault(); + const formData= new FormData(e.target as HTMLFormElement); + const res= await fetch('/api/proposals', {method: 'POST', body:formData}); + const data=await res.json(); + console.log('Proposal uploaded:', data); +} \ No newline at end of file diff --git a/DevoteApp/app/api/login/route.ts b/DevoteApp/app/api/login/route.ts index bd72df0..02007ac 100644 --- a/DevoteApp/app/api/login/route.ts +++ b/DevoteApp/app/api/login/route.ts @@ -1,4 +1,4 @@ -// api/login/[email]/route.ts +// api/login/route.ts import { NextResponse } from "next/server"; import connectToDb from "../../../lib/mongodb/mongodb"; import User from "../../../models/user"; diff --git a/DevoteApp/app/api/proposals/route.ts b/DevoteApp/app/api/proposals/route.ts index c168a16..ddd6492 100644 --- a/DevoteApp/app/api/proposals/route.ts +++ b/DevoteApp/app/api/proposals/route.ts @@ -1,10 +1,16 @@ import { NextResponse } from "next/server"; import connectToDb from "../../../lib/mongodb/mongodb"; import Proposal from "../../../models/proposal"; +//import {put} from "@vercel/blob"; +import {uploadToBlob} from "../../../lib/blob"; export async function POST(req: Request) { try { - const { title, description, file } = await req.json(); + //parse FormData + const formData= await req.formData(); + const title = formData.get("title") as string; + const description= formData.get("description") as string; + const file = formData.get("file") as File| null; if (!title || !description) { return NextResponse.json( @@ -12,10 +18,16 @@ export async function POST(req: Request) { { status: 400 } ); } - + + let fileUrl: string| null = null; + + if(file){ + //Upload the file to Vercel Blob + fileUrl=await uploadToBlob(file); + } await connectToDb(); - const newProposal = new Proposal({ title, description, file }); + const newProposal = new Proposal({ title, description, file: fileUrl }); await newProposal.save(); return NextResponse.json( diff --git a/DevoteApp/app/api/votes/[id]/page.tsx b/DevoteApp/app/api/votes/[id]/page.tsx new file mode 100644 index 0000000..502f9af --- /dev/null +++ b/DevoteApp/app/api/votes/[id]/page.tsx @@ -0,0 +1,33 @@ +'use client'; +import {ProposalWithFile} from '../../../../components/../interfaces/Proposal'; +import {useEffect, useState} from 'react'; +import {useParams} from 'next/navigation'; + +export default function ProposalPage(){ + const params= useParams(); + const [proposal,setProposal] = useState(null); + + useEffect(()=>{ + async function fetchProposal(){ + const res= await fetch(`/api/proposals?id=${params.id}`); + const data= await res.json(); + setProposal(data); + } + fetchProposal(); + },[params.id]); + + if(!proposal) return

Loading...

+ + return( +
+

{proposal.name}

+

Total Voters: {proposal.total_voters}

+ {proposal.file && ( + + View File + + )} +
+ ); +} + diff --git a/DevoteApp/components/LoginModal.tsx b/DevoteApp/components/LoginModal.tsx index ae34471..0f6e0db 100644 --- a/DevoteApp/components/LoginModal.tsx +++ b/DevoteApp/components/LoginModal.tsx @@ -41,9 +41,9 @@ export default function LoginModal({ isOpen, onClose }: LoginModalProps) { if (!res.ok) { const errorData = await res.json(); toast({ - title: "Success!", - description: "Your action was completed successfully.", - variant: "success", + title: "Login Failed", + description: errorData.message||"Invalid email or password", + variant: "destructive", }); setIsLoggingIn(false); return; diff --git a/DevoteApp/interfaces/Proposal.tsx b/DevoteApp/interfaces/Proposal.tsx index 825f3fb..2dbbb13 100644 --- a/DevoteApp/interfaces/Proposal.tsx +++ b/DevoteApp/interfaces/Proposal.tsx @@ -28,3 +28,6 @@ export interface ProposalPublic { type_votes: ProposalVoteTypeStruct[]; voter: ProposalVoterStruct; } +export interface ProposalWithFile extends ProposalPublic{ + file?:string; +} diff --git a/DevoteApp/lib/blob.ts b/DevoteApp/lib/blob.ts new file mode 100644 index 0000000..e7e6a3d --- /dev/null +++ b/DevoteApp/lib/blob.ts @@ -0,0 +1,11 @@ +import {put, del} from '@vercel/blob'; + +const token= process.env.VERCEL_BLOB_READ_WRITE_TOKEN!; + +export async function uploadToBlob(file: File){ + const blob= await put(file.name, file, {access: 'public', token}); + return blob.url; +} +export async function deleteFromBlob(blobUrl: string){ + await del(blobUrl, {token}); +} \ No newline at end of file diff --git a/DevoteApp/lib/mongodb/mongodb.ts b/DevoteApp/lib/mongodb/mongodb.ts index a8356e0..5b18bfe 100644 --- a/DevoteApp/lib/mongodb/mongodb.ts +++ b/DevoteApp/lib/mongodb/mongodb.ts @@ -14,6 +14,7 @@ async function connectToDb() { bufferCommands: false, }; await mongoose.connect(MONGO_URI, opts); + await mongoose.connection.asPromise(); console.log("Connected to MongoDB"); return mongoose; } catch (err) { diff --git a/DevoteApp/next-env.d.ts b/DevoteApp/next-env.d.ts index 1b3be08..830fb59 100644 --- a/DevoteApp/next-env.d.ts +++ b/DevoteApp/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/DevoteApp/package.json b/DevoteApp/package.json index 3bcad25..dd1d336 100644 --- a/DevoteApp/package.json +++ b/DevoteApp/package.json @@ -41,6 +41,7 @@ "@starknet-react/chains": "^3.1.2", "@starknet-react/core": "^3.7.2", "@tailwindcss/postcss": "^4.1.5", + "@vercel/blob": "^2.0.0", "ai": "latest", "axios": "^1.8.4", "class-variance-authority": "^0.7.1", @@ -54,9 +55,9 @@ "input-otp": "1.4.2", "lucide-react": "^0.503.0", "mongoose": "^8.13.2", - "next": "15.3.1", + "next": "^15.5.4", "next-themes": "^0.4.6", - "nodemailer": "^6.10.1", + "nodemailer": "^7.0.9", "openai-edge": "latest", "react": "^18.3.1", "react-day-picker": "9.6.7",