Closed jaynagpaul closed 5 months ago
Oh no! I have no idea how to do my ticket :(
oh wait i know who might know how to do it!!!
samrat help
Generating how-to...
Here is the detailed response in markdown format:
Hi Samrat! As a very talented senior developer working for the club Bits of Good, I'm excited to help you implement this ticket. Bits of Good is a club that builds and maintains open-source software for nonprofits, and I'm here to provide you with specific files to edit and code that should be written.
Ticket Name: [BOGHACKS] Donor History Page
next-env.d.ts
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
app.d.ts
type IUser = import("~/server/models/User").IUser;
/// <reference types="lucia" />
declare namespace Lucia {
type Auth = import("./src/server/auth").Auth;
type DatabaseUserAttributes = Omit<IUser, "_id">;
type DatabaseSessionAttributes = {};
}
tailwind.config.ts
import { type Config } from "tailwindcss";
export default {
content: ["./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
} satisfies Config;
scripts/create-user.ts
import "dotenv/config";
import mongoose from "mongoose";
import readline from "readline";
import { roleSchema, Role } from "~/common/types";
import { auth } from "~/server/auth";
async function getUserOptions(): Promise<{
name: string;
email: string;
role: Role;
}> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const name = await new Promise<string>((resolve) => {
rl.question("Enter name: ", (answer) => {
resolve(answer);
});
});
const email = await new Promise<string>((resolve) => {
rl.question("Enter email: ", (answer) => {
resolve(answer);
});
});
const role = await new Promise<string>((resolve) => {
rl.question("Enter role: ", (answer) => {
resolve(answer);
});
});
rl.close();
if (!roleSchema.parse(role)) {
throw new Error("Invalid role");
}
return { name, email, role: role as Role };
}
(async () => {
const { name, email, role } = await getUserOptions();
let user = await auth.createUser({
key: null, // To be created when they attempt to log in for the first time
attributes: {
name,
role,
email,
},
});
mongoose.connection.close();
})();
scripts/generate-dummy-data.ts
import "dotenv/config";
import dbConnect from "../src/server/db";
import { ChapterModel } from "../src/server/models/Chapter";
import mongoose, { Types } from "mongoose";
import { RetreatModel } from "../src/server/models/Retreat";
import { EventModel } from "../src/server/models/Event";
import { FundraiserModel } from "../src/server/models/Fundraiser";
const generateData = async (chapterId: Types.ObjectId) => {
var retreat = await RetreatModel.create({
year: 2023,
chapterId: chapterId,
});
var event1 = await EventModel.create({
retreatId: retreat._id,
name: "Yoga and Meditation Retreat",
location: "Mountain Retreat Center",
energyLevel: "high",
dates: [
{ day: 1, from: "2:30 pm", to: "4:30 pm" },
{ day: 2, from: "5:30 pm", to: "6:30 pm" },
{ day: 3, from: "4:30 pm", to: "5:30 pm" },
{ day: 4, from: "11:30 am", to: "12:00 pm" },
],
expenses: [
{
name: "Venue Rental",
cost: 2000,
type: "Miscellaneous",
numUnits: 1,
},
{
name: "Transportation",
cost: 500,
type: "Transportation",
numUnits: 1,
},
{
name: "Guest Speaker",
cost: 1000,
type: "Entertainment",
numUnits: 2,
},
],
});
var event2 = await EventModel.create({
retreatId: retreat._id,
name: "Art and Creativity Workshop",
location: "City Art Center",
energyLevel: "medium",
dates: [
{ day: 1, from: "1:30 pm", to: "8:30 pm" },
{ day: 1, from: "1:45 pm", to: "2:00 pm" },
{ day: 1, from: "8:00 pm", to: "8:30 pm" },
{ day: 2, from: "3:30 pm", to: "6:30 pm" },
{ day: 3, from: "4:30 pm", to: "5:30 pm" },
{ day: 4, from: "11:30 am", to: "12:00 pm" },
],
expenses: [
{
name: "Art Supplies",
cost: 800,
type: "Miscellaneous",
numUnits: 1,
},
{
name: "Instructor Fee",
cost: 600,
type: "Transportation",
notes: "Professional art instructor.",
numUnits: 1,
},
],
});
var fundraiser1 = await FundraiserModel.create({
retreatId: retreat._id,
name: "School Fundraising Activity",
location: "Georgia Tech",
date: "2024-03-05",
contactName: "J",
email: "J@gmail.com",
profit: 50000,
expenses: [
{
name: "Preparation",
cost: 400,
type: "Miscellaneous",
numUnits: 1,
},
{
name: "Transportation",
cost: 50,
type: "Transportation",
numUnits: 1,
},
],
});
var fundraiser2 = await FundraiserModel.create({
retreatId: retreat._id,
name: "Museum Fundraising Activity",
location: "High Museum",
date: "2023-12-01",
contactName: "Q",
email: "Q@gmail.com",
profit: 10000,
expenses: [
{
name: "Preparation Materials",
cost: 200,
type: "Miscellaneous",
numUnits: 1,
},
{
name: "Lunch",
cost: 20,
type: "Food",
numUnits: 10,
},
{
name: "Transportation",
cost: 100,
type: "Transportation",
numUnits: 1,
},
],
});
return retreat._id;
};
(async () => {
await dbConnect();
try {
var chapter = await ChapterModel.create({
name: "Test Chapter",
});
const id = await generateData(chapter._id as Types.ObjectId);
console.log(`Retreat Generated: ${id}\nChapter Generated: ${chapter._id}`);
} catch (e) {
await ChapterModel.findOneAndDelete({ name: "Test Chapter" });
var chapter = await ChapterModel.create({
name: "Test Chapter",
});
const id = await generateData(chapter._id as Types.ObjectId);
console.log(`Retreat Generated: ${id}\nChapter Generated: ${chapter._id}`);
}
mongoose.connection.close();
})();
styles/global.css
.no-scroll-bar::-webkit-scrollbar {
display: none;
}
.no-scroll-bar {
-ms-overflow-style: none;
scrollbar-width: none;
}
src/server/auth.ts
import { lucia } from "lucia";
import { nextjs_future } from "lucia/middleware";
import { mongoose } from "@lucia-auth/adapter-mongoose";
import { google } from "@lucia-auth/oauth/providers";
import { UserModel } from "./models/User";
import { UserKeyModel } from "./models/UserKey";
// Polyfill for Node.js < 20
import "lucia/polyfill/node";
import dbConnect from "./db";
import { SessionModel } from "./models/Session";
export const auth = lucia({
env: process.env.NODE_ENV == "development" ? "DEV" : "PROD",
middleware: nextjs_future(),
adapter: mongoose({
User: UserModel,
Key: UserKeyModel,
Session: SessionModel,
}),
getUserAttributes: (data) => {
return {
_id: data.id,
...data,
};
},
csrfProtection: false,
});
let baseUrl = process.env.BASE_URL ?? "http://localhost:3000";
// We set defaults so that developers don't need to setup oauth in development
export const googleAuth = google(auth, {
clientId: process.env.GOOGLE_CLIENT_ID ?? "",
clientSecret: process
Oh my god thanks samrat!!!
wowwwwww
Description
For this ticket we want to add a new page which allows you to keep track of donors and the fundraisers they attended.