Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions DevoteApp/.env.local
Original file line number Diff line number Diff line change
@@ -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

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
7 changes: 7 additions & 0 deletions DevoteApp/app/admin/create-proposal/page.tsx
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 1 addition & 1 deletion DevoteApp/app/api/login/route.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
18 changes: 15 additions & 3 deletions DevoteApp/app/api/proposals/route.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
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(
{ message: "Title and description are required" },
{ 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(
Expand Down
33 changes: 33 additions & 0 deletions DevoteApp/app/api/votes/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -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<ProposalWithFile| null>(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 <p>Loading...</p>

return(
<div>
<h1>{proposal.name}</h1>
<p>Total Voters: {proposal.total_voters}</p>
{proposal.file && (
<a href={proposal.file} target="_blank" rel="noopener noreferrer">
View File
</a>
)}
</div>
);
}

6 changes: 3 additions & 3 deletions DevoteApp/components/LoginModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions DevoteApp/interfaces/Proposal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ export interface ProposalPublic {
type_votes: ProposalVoteTypeStruct[];
voter: ProposalVoterStruct;
}
export interface ProposalWithFile extends ProposalPublic{
file?:string;
}
11 changes: 11 additions & 0 deletions DevoteApp/lib/blob.ts
Original file line number Diff line number Diff line change
@@ -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});
}
1 change: 1 addition & 0 deletions DevoteApp/lib/mongodb/mongodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions DevoteApp/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
5 changes: 3 additions & 2 deletions DevoteApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down