# Project export: Bartr

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: bartering app
- Devpost: https://devpost.com/software/bartr-z2q4x6
- GitHub: https://github.com/apolyeti/bartr/
- Team: 4 GitHub contributor(s) — apolyeti (32 commits), Hovhannes Muradyan (28 commits), 804115 (26 commits), Nicholas (13 commits)

## Devpost submission (written by the team)

### Inspiration

Drawing inspiration from platforms like Ebay, Craigslist, and Facebook Marketplace, which facilitate the exchange of goods and services, we envisioned a unique approach. Our goal was to redefine the transactional aspect by introducing a goodwill system, where users engage in mutually beneficial exchanges.

### What it does

Our platform allows users to showcase items or services they are willing to share, seeking something in return. The essence lies in fostering connections as users can reach out to potential trading partners through their profiles to initiate a "trade."

### How we built it

Utilizing Next.js, Material UI, and Prisma (SQL) for database management, we meticulously crafted the platform. The synergy of these technologies enabled a seamless and efficient development process. Challenges we faced While some team members were adept with the tech stack, opting for the latest version of Next.js posed a challenge. Despite a learning curve and increased time spent on documentation, we navigated through, emphasizing collaboration over individual familiarity. Accomplishments we're proud of For many team members, it was a journey of first-time experiences with Next.js and React. Despite two team members facing unforeseen obstacles, the remaining two exhibited commendable resilience. Our collective progress and expanded skill set showcase our commitment and determination.

### What we learned

Exploring Next.js's unique features in web development, such as server components, enriched our understanding. Many of us gained insights into API interactions, including calling external APIs and creating our own within Next. Implementing a Google Authentication system restricted to @ucsc.edu domains added a layer of security and expertise to our skill set.

### What's next

Our future goals include finding a suitable CDN service for hosting images. Although we encountered challenges due to paywalls within the available options, the importance of image hosting in our project's growth is undeniable. As we expand, securing a reliable CDN becomes a priority.

## README (from the GitHub repository)

# bartr

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.


## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 41 KB.
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (37 of 37)

```
.eslintrc.json
.gitignore
next.config.mjs
package.json
prisma/migrations/20240120224159_init/migration.sql
prisma/migrations/20240121032300_added_image_link_to_post/migration.sql
prisma/migrations/20240121042608_made_name_required/migration.sql
prisma/migrations/migration_lock.toml
prisma/schema.prisma
prisma/seed.ts
README.md
src/app/api/auth/[...nextauth]/route.ts
src/app/api/itemuserid/route.ts
src/app/api/newItem/route.ts
src/app/api/removeItem/route.ts
src/app/api/user/route.ts
src/app/api/userid/route.ts
src/app/create/post/page.tsx
src/app/font.css
src/app/layout.tsx
src/app/not-found.tsx
src/app/page.tsx
src/app/post/[post]/page.tsx
src/app/profile/[user]/page.tsx
src/app/themes.ts
src/components/ItemComponents/ItemPost.tsx
src/components/ItemComponents/ItemRemoveButton.tsx
src/components/MainPage/Header.tsx
src/components/MainPage/NavBar.tsx
src/components/MainPage/Providers.tsx
src/components/MainPage/Selection.tsx
src/types/db.ts
src/types/types.ts
src/utils/cloudinary.ts
src/utils/db.ts
src/utils/types.ts
tsconfig.json
```

### Dependencies

- package.json: @cloudinary/react@^1.11.2, @cloudinary/url-gen@^1.16.0, @emotion/cache@^11.11.0, @emotion/react@^11.11.3, @emotion/server@^11.11.0, @emotion/styled@^11.11.0, @mui/icons-material@^5.15.5, @mui/material@^5.15.5, @mui/material-nextjs@^5.15.5, @nextui-org/react@^2.2.9, @prisma/client@^5.8.1, @types/node@^20, @types/react@^18, @types/react-dom@^18, @uploadthing/react@^6.2.0, axios@^1.6.7, cloudinary@^1.41.3, eslint@^8, eslint-config-next@14.1.0, fs@^0.0.1-security, next@14.1.0, next-auth@^4.24.5, node-fetch@^2.7.0, prisma@^5.8.1, react@^18, react-cloudinary-upload-widget@^2.0.0, react-dom@^18, ts-node@^10.9.2, typescript@^5, uploadthing@^6.2.0

### Recent commits (newest first)

- README
- this shits a mess:
- holy moly it works
- cloudinary not done yet
- renamed the folder, youre welcome apolyeti
- weird system
- semi working posts
- push
- idk
- remove item api
- im going to kms
- description
- fix showall
- fuck this shit
- fix showall
- ?
- Merge branch 'main' of github.com:apolyeti/bartr
- Post item and fix location
- hm
- new item

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
    "name": "bartr",
    "version": "0.1.0",
    "private": true,
    "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start",
        "lint": "next lint"
    },
    "prisma": {
        "seed": "ts-node prisma/seed.ts"
    },
    "dependencies": {
        "@cloudinary/react": "^1.11.2",
        "@cloudinary/url-gen": "^1.16.0",
        "@emotion/cache": "^11.11.0",
        "@emotion/react": "^11.11.3",
        "@emotion/server": "^11.11.0",
        "@emotion/styled": "^11.11.0",
        "@mui/icons-material": "^5.15.5",
        "@mui/material": "^5.15.5",
        "@mui/material-nextjs": "^5.15.5",
        "@nextui-org/react": "^2.2.9",
        "@prisma/client": "^5.8.1",
        "@uploadthing/react": "^6.2.0",
        "axios": "^1.6.7",
        "cloudinary": "^1.41.3",
        "fs": "^0.0.1-security",
        "next": "14.1.0",
        "next-auth": "^4.24.5",
        "node-fetch": "^2.7.0",
        "react": "^18",
        "react-cloudinary-upload-widget": "^2.0.0",
        "react-dom": "^18",
        "ts-node": "^10.9.2",
        "uploadthing": "^6.2.0"
    },
    "devDependencies": {
        "@types/node": "^20",
        "@types/react": "^18",
        "@types/react-dom": "^18",
        "eslint": "^8",
        "eslint-config-next": "14.1.0",
        "prisma": "^5.8.1",
        "typescript": "^5"
    }
}

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
import NavBar from "@components/MainPage/NavBar";

import theme from "./themes";
import { CssBaseline, ThemeProvider } from "@mui/material";
import Providers from "@/components/MainPage/Providers";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <html lang="en">
        <body>
        <Providers>
        <NavBar/>
        <AppRouterCacheProvider>
          {children}
        </AppRouterCacheProvider>
        </Providers>
        </body>
      </html>
    </ThemeProvider>
  );
}

```

### src/app/page.tsx

```typescript
// import { getUserById } from "@/utils/db";
import prisma from "@/utils/db";
import ItemPost from "@/components/ItemComponents/ItemPost";
import { Container, Grid } from "@mui/material";
import Header from "@/components/MainPage/Header";
export default async function Home() {

  // const user = await prisma.user.findUnique({
  //   where: {
  //     id: 1,
  //   },
  // });

  const posts = await prisma.post.findMany({}).then((posts) => {
    return posts.map((post) => ({
      id: post.id,
      title: post.title,
      content: post.content,
      image: post.image,
    }));
  });


  
  return (
    // <Typography>{user.name}</Typography>
    <>
      <Header />
      <Container>
        <Grid container spacing={10}>
            {posts.map((post) => (
              <Grid item xs={3} key={post.id}>
                  <ItemPost item={post} showAll={true}/>
              </Grid>
            ))}
        </Grid>
    </Container>
    </>
    /*
      <AppBar>
        <Toolbar>
          <Box flexGrow={1}></Box>
          <Image
            src= "/bartrlogo.svg"
            alt="logo"
            width={400}
            height={80}
          />
          
          <Stack spacing={2} direction="row" >
            <Button variant="contained">LOG IN</Button>
            <Button variant="outlined">SIGN UP</Button>
          </Stack>
        </Toolbar>
      </AppBar>
    */
  );
}

```

### src/app/api/itemuserid/route.ts

```typescript
import prisma from "@/utils/db";

export async function GET(req: Request, res: Response) {
    console.log("lol", req)
    const item = await prisma.post.findMany({
        where: {
            id: 1
        }
    });

    return Response.json(item[0].authorId);
}
```

### src/app/api/removeItem/route.ts

```typescript
import prisma from "@/utils/db";

export async function DELETE(req: Request, res: Response) {
    // body will consist of post id
    const body = await req.json();
    const postId = body.postId;

    // find post by id and remove it
    
    const post = await prisma.post.delete({
        where: {
            id: postId
        }
    });

    console.log('this is post')
    console.log(post);

    return Response.json({ success: true })
}
```

### src/app/api/userid/route.ts

```typescript
import prisma from "@/utils/db";

export async function POST(req: Request, res: Response) {
    const body = await req.json();
    const email = body.email;
    if (email) {
        // find userid by email
        const user = await prisma.user.findUnique({
            where: {
                email: email,
            },
        });
        if (user) {
            return Response.json({ success: true, userId: user.id })
        }
    }
    return Response.json({ success: false })
}
```

### src/app/api/newItem/route.ts

```typescript
import prisma from "@/utils/db";
import type { NextApiRequest, NextApiResponse } from 'next'

export async function POST(req: NextApiRequest, res: NextApiResponse) {

    let { body } = req;
    let passedValue = await new Response(body).text();
    body = JSON.parse(passedValue);

    console.log('this is the body')
    console.log(body)

    const email = body.author;
    let userId = -5;
    // find userid by email
    const user = await prisma.user.findUnique({
        where: {
            email: email,
        },
    });

    // add to prisma database
    if (user) {
        userId = user.id;
    }
    const newItem = await prisma.post.create({
        data: {
            title: body.title,
            content: body.content,
            image: body.image,
            published: true,
            author: {
                connect: { id: userId }
            },
        },
    });
    console.log('this is newItem')
    console.log(newItem);

    return Response.json({ success: true })
}
```

### src/app/api/user/route.ts

```typescript
// pages/api/user.js
import prisma from "@/utils/db";
import { NextApiRequest, NextApiResponse } from 'next';


export async function POST(request: Request, res: Response) {

    const body = await request.json();
  
    
    if (body && body.name && body.email) {
      const user = await prisma.user.findUnique({
        where: {
          email: body.email,
        },
      });
      console.log("User:", user);
  
      if (!user) {
        await prisma.user.create({
          data: {
            email: body.email,
            name: body.name,
            location: "College 10",
          },
        });
      }
    }
  
    //res.status(200).json({ success: true });
    return Response.json({ success: true })
  }

// export default async function handler(req : NextApiRequest, res: NextApiResponse) { 
//     console.log('test')
//   const { session } = req.body;

//   if (session && session.user?.email && session.user?.name) {
//     const user = await prisma.user.findUnique({
//       where: {
//         email: session.user.email,
//       },
//     });

//     if (!user) {
//       await prisma.user.create({
//         data: {
//           email: session.user.email,
//           name: session.user.name,
//           location: "College 10",
//         },
//       });
//     }
//   }

//   res.status(200).json({ success: true });
// }

```

### src/app/post/[post]/page.tsx

```typescript
import Stack from '@mui/material/Stack';

import prisma from "@/utils/db";
import { notFound } from 'next/navigation';
import ItemPost from '@/components/ItemComponents/ItemPost';
import { Box, Button, Container, Typography } from '@mui/material';

import ItemRemoveButton from '@/components/ItemComponents/ItemRemoveButton';

export default async function Page({ params }: { params: { post: string } }) {
    
    let userId;
    const post = await prisma.post.findUniqueOrThrow({
        where: {
          id: parseInt(params.post),
        }}).then((post) => {
            userId = post.authorId;
            return {
                id: post.id,
                title: post.title,
                content: post.content,
                image: post.image,
            };
        }).catch((error) => {
            // make 404 page
            return notFound();
        });
    const user = await prisma.user.findUnique({
        where: {
          id: userId,
        },
    }) || {name: "User not found"};

    return (
        <Container>
            <Stack direction="row" >
                <Stack direction={"column"} spacing={2}>
                    <ItemPost item={post} showAll={true}/>
                    <ItemRemoveButton itemId={post.id}/>
                </Stack>
                <Box>
                    <Typography fontWeight="thin" variant="h5">{user.name}</Typography>
                    <Typography fontStyle="italic" fontWeight="thin" fontFamily="monospace" variant="h6">{post.content}</Typography>
                </Box>
            </Stack>
        </Container>
    ); 
}
```

### src/app/profile/[user]/page.tsx

```typescript
import Avatar from '@mui/material/Avatar';
import Stack from '@mui/material/Stack';
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import prisma from '@/utils/db';
import ItemPost from '@/components/ItemComponents/ItemPost';
import { notFound } from 'next/navigation';
import Divider from '@mui/material/Divider';

function stringAvatar(name: string) {
  return {
    sx: {
      bgcolor: "primary.main",
    },
    children: `${name.split(' ')[0][0]}${name.split(' ')[1][0]}`,
  };
}

export default async function Page({ params }: { params: { user: string } }) {

  const user = await prisma.user.findUniqueOrThrow({
    where: {
      id: parseInt(params.user),
    },
    }).catch((error) => {
        // make 404 page
        return notFound();
        }
    );

    const posts = await prisma.post.findMany({
      where: {
        authorId: parseInt(params.user),
      },
    }).then((posts) => {
      return posts.map((post) => ({
        id: post.id,
        title: post.title,
        content: post.content,
        image: post.image,
      }));
    });

    

    return (
      <Stack direction="row" alignItems={"flex-start"} sx={{
        alignItems: "left",
        width: "100%", 
        padding: "1rem",
        marginRight: "10px",
      }}>

        <Stack spacing={2} direction="row" sx={{
          padding: "4rem",
        }}>
          <Avatar {...stringAvatar(user.name)} sx={{
            width: 200, height:200, fontSize: 64
          }} />
          <Stack spacing={2} direction="column" sx={{
          padding: "4rem",
          }}>
            <Typography fontSize={25}>{user.name}</Typography>
            <Divider />

            <Box >
              <Typography fontSize={15}>{user.email}</Typography>
              <Typography fontSize={15}>Location: {user.location}</Typography>
            </Box>
          </Stack>
        </Stack>

        <Stack spacing={2} sx={{
          padding: "4rem",
        }}>
          <Typography fontSize={25}>Listings</Typography>
            <Stack direction="row">
                {posts.map((post) => (
                  <span>
                    <ItemPost item={post} showAll={false} key={post.id}/>
                  </span>
                ))}
            </Stack>
        </Stack>

    </Stack>
    ); 
}


```

[20 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]