# Project export: Ayllu

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: Cal Hacks 11.0
- Tagline: Keep long-distance families close together! Mood tracking and event planning app.
- Devpost: https://devpost.com/software/ayllu
- GitHub: https://github.com/no-way-joses/ayllu
- Team: 2 GitHub contributor(s) — Ethan Ayaay (7 commits), Susana Chang (3 commits)

## Devpost submission (written by the team)

### Overview

Background As college students, there are times when we definitely feel the distance being away from our loved ones. During the academic year, it can be hard to find time to talk with them, especially with how hectic our schedules can be. We wanted to create an app to close the distance with our families, or anyone long-distance that we miss! Functions Mood Tracker! Choose from 5 different moody dogs to "check-in" on how your day was! After checking in, you can see a feed on how the rest of your "family" is doing! Event Planner! With the help of Gemini AI, create different events with your family and track them in a feed-style! Gemini AI automatically suggests an event depending on the time of the year! Tech Stack Front End - Tailwind CSS, Next.js Back End - Python, Clerk, API Gateway Database - dynamoDB

### Challenges we ran into

Setting up a secure user authentication system while maintaining a user-friendly experience was a challenge we had to overcome. Throughout the development process, we had to learn and adapt to new technologies, including Tailwind CSS and Next.js, which required time and effort to become proficient in using them effectively.

### Accomplishments we're proud of

We proudly implemented the mood tracker feature, allowing users to express their feelings creatively through personalized icons. We designed an intuitive and visually appealing user interface, making it easy for family members of all ages, specially elderly people, to navigate and interact with the app. The integration of Gemini AI to suggest events based on the time of year was a significant achievement, enhancing family engagement.

### What we learned

Working as a team highlighted the importance of effective collaboration and communication. We developed better strategies for sharing ideas, troubleshooting issues, and managing project timelines, which strengthened our teamwork. We enhanced our technical skills by learning new technologies.

### What's next

Our next step is to expand the AI features to offer more personalized event suggestions based on user preferences and location. We plan to introduce a daily check-in question feature to prompt family members to share what’s on their mind. We’re also working on displaying the status of family members, so users can quickly see updates on their loved ones. Additionally, we'll be implementing an event countdown feature, letting families track how soon their upcoming plans will happen, building excitement and anticipation. We also want to implement uploading photos to the events and everyday photos, and utilizing AI to create a family photo album and videos allowing families to relive memories together.

## README (from the GitHub repository)

# AYLLU

![Ayllu Welcome Page](photos/1.png)

## Background
As college students, there are times when we definitely feel the distance being away from our families. During the academic year, it can be hard to find time to talk with them especially with how hectic our schedules can be. We wanted to create an app to close the distance with our families, or anyone long-distance that we miss!

## Functions
###Mood Tracker!
Choose from 5 different moody dogs to "check-in" on how your day was! After checking in, you can see a feed on how the rest of your "family" is doing!

###Event Planner!
With the help of Gemini AI, create different events with your family and track them in a feed-style! Gemini AI automatically suggests an event depending on the time of the year!

## Tech Stack
- Front End - Tailwind CSS, Next.js
- Back End - Python, Clerk, API Gateway
- Database - dynamoDB

## Challenges we ran into

Setting up a secure user authentication system while maintaining a user-friendly experience was a challenge we had to overcome. Throughout the development process, we had to learn and adapt to new technologies, including Tailwind CSS and Next.js, which required time and effort to become proficient in using them effectively.

## Accomplishments that we're proud of

We proudly implemented the mood tracker feature, allowing users to express their feelings creatively through personalized icons. We designed an intuitive and visually appealing user interface, making it easy for family members of all ages, specially elderly people, to navigate and interact with the app. The integration of Gemini AI to suggest events based on the time of year was a significant achievement, enhancing family engagement.

## What we learned

Working as a team highlighted the importance of effective collaboration and communication. We developed better strategies for sharing ideas, troubleshooting issues, and managing project timelines, which strengthened our teamwork. We enhanced our technical skills by learning new technologies.

## What's next for Ayllu

Our next step is to expand the AI features to offer more personalized event suggestions based on user preferences and location. We plan to introduce a daily check-in question feature to prompt family members to share what’s on their mind. We’re also working on displaying the status of family members, so users can quickly see updates on their loved ones. Additionally, we'll be implementing an event countdown feature, letting families track how soon their upcoming plans will happen, building excitement and anticipation. We also want to implement uploading photos to the events and everyday photos, and utilizing AI to create a family photo album and videos allowing families to relive memories together.


## Detected evidence (automated analysis)

Indexed codebase: 33 recognized source files, 48 KB.
- CSS (language) — detected in the code
- Google Gemini (technology) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- AWS (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (39 of 39)

```
.eslintrc.json
.gitignore
app/components/Navbar.tsx
app/details/page.tsx
app/events/page.tsx
app/globals.css
app/home/_components/EventModal.tsx
app/home/_components/Events.tsx
app/home/_components/MoodBar.tsx
app/home/_components/MoodFeed.tsx
app/home/_components/MoodFeedCard.tsx
app/home/_components/MoodModal.tsx
app/home/create/page.tsx
app/home/page.tsx
app/layout.tsx
app/page.tsx
app/signin/[[...signin]]/page.tsx
app/signup/[[...signup]]/page.tsx
backend/familyAddMember-c1e5878c-b84a-4752-818e-dd83c6214225/lambda_function.py
backend/familyChangeName-6aea3b03-e4ce-4800-b6cb-cf0ca51e7f3e/lambda_function.py
backend/familyCreate-28bfcf2c-6675-44ac-8eee-361b1d617ae2/lambda_function.py
backend/familyGet-9d0199b8-149d-49ad-92d5-af3c73be43d8/lambda_function.py
backend/moodCreate-2234afca-420d-4bb6-bf98-8787240828b2/lambda_function.py
backend/moodGet-2393b175-38f5-4866-8f33-4f8d7cc7c122/lambda_function.py
backend/moodGetFromDate-642f23eb-916b-4da7-8520-680acd490071/lambda_function.py
backend/planCreate-bfec432c-b103-42da-b6ab-a59e49e5a535/lambda_function.py
backend/planGet-c1f361a0-64f5-4862-bd2a-f1fa8ef4a689/lambda_function.py
backend/userChangeFamily-62cb7e6f-034d-4379-9bc5-d1302c3d1d8a/lambda_function.py
backend/userChangeName-d89fe9cd-3b6d-4fea-9bb7-1c1886d7a9a0/lambda_function.py
backend/userChangeProfile-98f6d301-1c22-4f0b-8fcf-4f0a1709fd95/lambda_function.py
backend/userCreate-66c3d940-fb88-4e57-8344-9529474bf0f8/lambda_function.py
backend/userGet-d21b641f-8e0b-49ef-bdbf-17a21eb0bf52/lambda_function.py
middleware.ts
next.config.mjs
package.json
postcss.config.mjs
README.md
tailwind.config.ts
tsconfig.json
```

### Dependencies

- package.json: @clerk/nextjs@^5.7.5, @clerk/themes@^2.1.37, @google/generative-ai@^0.21.0, @types/node@^20, @types/react@^18, @types/react-dom@^18, axios@^1.7.7, eslint@^8, eslint-config-next@14.2.15, next@14.2.15, postcss@^8, react@^18, react-dom@^18, react-icons@^5.3.0, tailwindcss@^3.4.1, tailwindcss-animated@^1.1.2, typescript@^5

### Recent commits (newest first)

- sdhuashdsui
- readme
- Merge pull request #1 from no-way-joses/test
- day 3
- events n connection to gemini
- backend stuff
- gg
- bad wifi
- mood modalsss
- first commit
- Initial commit from Create Next App

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

### package.json

```
{
  "name": "ayllu",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@clerk/nextjs": "^5.7.5",
    "@clerk/themes": "^2.1.37",
    "@google/generative-ai": "^0.21.0",
    "axios": "^1.7.7",
    "next": "14.2.15",
    "react": "^18",
    "react-dom": "^18",
    "react-icons": "^5.3.0",
    "tailwindcss-animated": "^1.1.2"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.15",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

```

### app/layout.tsx

```typescript

import type { Metadata } from "next";
import { Roboto } from "next/font/google";
// import localFont from "next/font/local";
import "./globals.css";
import { ClerkProvider } from "@clerk/nextjs";
import Navbar from './components/Navbar';


// const geistSans = localFont({
//   src: "./fonts/GeistVF.woff",
//   variable: "--font-geist-sans",
//   weight: "100 900",
// });
// const geistMono = localFont({
//   src: "./fonts/GeistMonoVF.woff",
//   variable: "--font-geist-mono",
//   weight: "100 900",
// });

const roboto = Roboto({
  subsets: ["latin"],
  weight: "500",
  display: "swap"
});

export const metadata: Metadata = {
  title: "AYLLU",
  description: "Keep your family close",
  icons: {
    icon: "/favicon.ico",
    shortcut: "/favicon.ico",
    apple: "/favicon.ico",
  },
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {


  return (

    <ClerkProvider>
      <html lang="en">
        <body
          className={`${roboto.className} w-screen h-screen antialiased bg-gradient-to-b from-orange-500 to-orange-400 text-slate-50`}
          >
          <div className="flex w-full h-full gap-2">
            <Navbar />
            {children}
          </div>
        </body>
      </html>
    </ClerkProvider>
  );
}

```

### app/page.tsx

```typescript
"use client"

import Image from "next/image";
import { useRouter } from "next/navigation";
import Navbar from "./components/Navbar";

import { useEffect, useRef, useState } from "react";

export default function Home() {
  const router = useRouter();

  const [sidebarVisible, setSidebarVisible] = useState(false);
  const navbarRef = useRef<HTMLDivElement>(null);

  const onSignin = () => {
    router.push('/signin');
  }

  const onSignup = () => {
    router.push('/signup');
  }

  const toggleNavbar = () => {
    setSidebarVisible (!sidebarVisible);
  };

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (navbarRef.current && !navbarRef.current.contains(event.target as Node))  
 {
        setSidebarVisible(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, []);


  return (
    // if the user isn't logged in / authenticated, redirect to login
    <div className="h-full w-full">
      <div className="flex flex-col justify-center items-center w-full h-full">
        <div>
          <Image alt="logo" src="/logo.png" width="400" height="400" className="animate-fade animate-delay-7300"/>
          <h1 className="text-4xl text-center font-bold drop-shadow-sm animate-fade-up animate-ease-out animate-delay-900"> Welcome to AYLLU! </h1>
          <h2 className="text-center mt-4 animate-fade-up animate-ease-out animate-delay-700"> where family stays close </h2>
        </div>
        <div className="flex flex-col h-[30%] w-[70%] lg:w-[40%] justify-center">
          <div  onClick={onSignin}
                className="text-center leading-10 backdrop-blur-sm rounded-3xl hover:cursor-pointer bg-transparent/20 hover:bg-transparent/40 transition-colors p-5 border-5 border-shadow">
            <button>
              Login
            </button>
          </div>
          <div  onClick={onSignup}
                className="text-center mt-4 leading-10 backdrop-blur-sm rounded-3xl hover:cursor-pointer bg-transparent/20 hover:bg-transparent/40 transition-colors p-5 border-5 border-shadow">
            <button>
              Create Account
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

```

### app/details/page.tsx

```typescript
"use client"

import Image from "next/image";
import Navbar from "../components/Navbar";
import axios from "axios";

import { useEffect, useState } from "react";
import { useUser } from "@clerk/clerk-react";

export default function Details() {
  const [ familyId, setFamilyId ] = useState('');
  const {user, isLoaded} = useUser()

  useEffect(() => {
    if (!isLoaded) return;

    axios.post(`${process.env.NEXT_PUBLIC_API}/user/get`, {
      userId: user?.id,
     })
    .then((res) => {
      console.log('Getting family details', JSON.parse(res.data.body).Item.familyId);
      let currentFamilyId = JSON.parse(res.data.body).Item.familyId
      setFamilyId(currentFamilyId);
    })
    .catch((err) => {
      console.log('POST error', err);
    })
  }, [])

  return (
  <div className="w-screen h-screen">
       <div className=" z-20 flex flex-col justify-center items-center w-screen h-screen text-neutral-800">
        <div className="mx-11 leading-10 backdrop-blur-sm rounded-3xl bg-transparent/20 p-5 border-5 border-shadow">
          <h1 className=" text-lg text-start items-center whitespace-pre-line">Family ID:</h1>
          <p className="text-2xl text-left indent-5 whitespace-break-spaces">a16f0cbe-e072-4bf4-b7d1-cecd4ac7c0e2</p>
          <p className="text-lg text-end">END OF DETAILS</p>
        </div>
      </div>
    </div>
  )
}


```

### app/home/page.tsx

```typescript
"use client"
import { useRouter } from "next/navigation";
import { useUser } from "@clerk/clerk-react";
import axios from "axios";
import Image from "next/image";

import { IoCalendarNumberOutline } from "react-icons/io5";

import Navbar from "../components/Navbar";

import { useEffect, useRef, useState } from "react";
import MoodFeed from "./_components/MoodFeed";
import MoodModal from "./_components/MoodModal";
import EventModal from "./_components/EventModal";

export default function Home() {
  const [ hasFamily, setFamily ] = useState(false);
  const [ familyId, setFamilyId ] = useState('');
  const [ eventModal, setEventModal ] = useState(false);
  const [ modalOpen, setModalOpen ] = useState(true); // TODO: change back to true

  console.log('is this true', hasFamily)

  const router = useRouter();
  const { user, isLoaded } = useUser();
  const codeRef = useRef(null);

  const onCreate = () => {
    router.push('/home/create');
  }

  useEffect(() => {
    if (!isLoaded) return;

    axios.post(`${process.env.NEXT_PUBLIC_API}/user`, {
      userId: user?.id,
      name: user?.firstName
    })
    .then((res) => {
      console.log('POST success', res);
    })
    .catch((err) => {
      console.log('POST error', err);
    })

    console.log('user id', user?.id)

    axios.post(`${process.env.NEXT_PUBLIC_API}/user/get`, {
      userId: user?.id
    })
    .then(res => {
      console.log('SUCCESS get user', JSON.parse(res.data.body).response.Item.familyId)

      const famId = JSON.parse(res.data.body).response.Item.familyId

      // TODO: update hasFamily state to true if family id exists
      if (famId !== '0') {
        setFamily(true);
        setFamilyId(famId);
      }
    })
    .catch(err => {
      console.log('ERROR get user', err)
    })
  }, [isLoaded, user])

  const onJoin = () => {
    let familyId = codeRef.current.value;

    if (user?.id) {
      axios.put(`${process.env.NEXT_PUBLIC_API}/user/family`, {
        userId: user?.id,
        familyId
      })
      .then(res => {
        console.log('SUCCESS join', res);
        router.push('/home');
      })
      .catch(err => {
        console.log('ERROR join', err);
      })
    }
  }

  return (
    <div className="w-screen h-screen">
      { hasFamily ? (
        <div className="relative h-full w-full flex flex-col">
          { eventModal && <EventModal setEventModal={setEventModal}/> }
          <div onClick={() => {setEventModal(true)}} className="fixed z-[999] mb-4 mr-4 bottom-4 right-4 rounded-full bg-orange-600 h-20 w-20 drop-shadow-lg hover:cursor-pointer hover:bg-orange-700 flex justify-center items-center">
            <IoCalendarNumberOutline className="h-12 w-12"/>
          </div>
          <MoodFeed familyId={familyId}/>
        </div>
      )
      :
        <div className="h-full w-full flex flex-col justify-center gap-12 items-center">
          <Image alt="logo" src="/logo.png" width="400" height="400"/>
          <h1 className="font-bold drop-shadow-sm text-3xl mt-0">Welcome to AYLLU!</h1>
          <div className="w-[70%] lg:w-[40%] flex flex-col gap-4 items-center">
            <div className="text-center w-80 leading-10 backdrop-blur-sm rounded-3xl hover:cursor-pointer bg-transparent/20 hover:bg-transparent/40 transition-colors p-2 border-5 border-shadow">
              <button onClick={onCreate}>
                Create a Family
              </button>
            </div>
            <div className="flex flex-col">
              <p className="text-center font-bold">or join an existing family</p>
              <div className="text-center leading-10 p-5 border-5 border-shadow flex">
                <input ref={codeRef} placeholder="family id" className="text-center rounded-tl-xl rounded-bl-xl text-black"></input>
                <button onClick={onJoin} className="bg-transparent/20 hover:bg-transparent/40 transition-colors rounded-tr-xl rounded-br-xl px-12">
                  Join
                </button>
              </div>
            </div>
          </div>
        </div>
      }
      {
        (modalOpen && hasFamily)  && <MoodModal setModalOpen={setModalOpen}/>
      }
    </div>
  );
}

```

### app/events/page.tsx

```typescript
"use client"

import axios from 'axios';
import { useEffect, useState } from 'react';
import { GoogleGenerativeAI } from "@google/generative-ai";
const genAI = new GoogleGenerativeAI(process.env.NEXT_PUBLIC_GEMINI); // <--- here API KEY
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
const prompt = "Create just ONE title (NOTHING ELSE, JUST THE TITLE) of recommendation of an event for families who are at a distance. If you can, also take into account special events depending on the month.";
const prompt2 = "Using the next title, CREATE JUST A SMALL DESCRIPTION of the event AND NOTHING ELSE: ";
let generatedTitle = "";
let generatedDescription = "";

(async () => {
    const result = await model.generateContent(prompt);
    generatedTitle = result.response.text();
    console.log(generatedTitle);


    const result2 = await model.generateContent(prompt2 + generatedTitle);
    generatedDescription = result2.response.text();
    console.log(generatedDescription);
})();

interface Event {
    title: string;
    startDate: string;
    description?: string;
    endDate?: string;
    startHour?: string;
    endHour?: string;
    familyId: string;
}

export default function Event() {
    const [events, setEvents] = useState<Event[]>([]);
    const [newEvent, setNewEvent] = useState<Event>({
        title: '',
        startDate: '',
        description: '',
        endDate: '',
        startHour: '',
        endHour: '',
        familyId: '1', // <--- hardcoded for now
    });

    useEffect(() => {
        axios.post(`${process.env.NEXT_PUBLIC_API}/plan/get`, {
            familyId: "1", // <--- hardcoded for now
            startDate: "2021-09-01" // <--- hardcoded for now
          })
            .then(response => {
                console.log('Events fetched:', JSON.parse(response.data.body)['plans']);
                setEvents(JSON.parse(response.data.body)['plans'])
            })
            .catch(error => console.error('Error fetching events:', error));
    }, []);

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setNewEvent(prevState => ({ ...prevState, [name]: value }));
    };

    const handleCreateEvent = () => {
        axios.post(`${process.env.NEXT_PUBLIC_API}/plan`, newEvent)
            .then(response => {
                console.log('Event created:', response.data);
                setEvents([...events, newEvent]);
                setNewEvent({
                    title: '',
                    startDate: '',
                    description: '',
                    endDate: '',
                    startHour: '',
                    endHour: '',
                    familyId: '1' // <--- hardcoded for now
                });
            })
            .catch(error => console.error('Error creating event:', error));
    };

    return (
        <div className="w-full h-full flex flex-col justify-center items-center">
            <div>

                {events.map((event, index) => (
                    <div key={index} className="event-card">
                        <h2>{event.title}</h2>
                        <p>Start Date: {event.startDate}</p>
                        {event.description && <p>Description: {event.description}</p>}
                        {event.endDate && <p>End Date: {event.endDate}</p>}
                        {event.startHour && <p>Start Hour: {event.startHour}</p>}
                        {event.endHour && <p>End Hour: {event.endHour}</p>}
                    </div>
                ))}

            </div>
            <div className="create-event-card bg-orange-700 rounded-xl flex flex-col items-center gap-4 text-center p-6">
                <h2 className="text-xl">Create Event</h2>
                <input
                    type="text"
                    name="title"
                    value={newEvent.title}
                    onChange={handleInputChange}
                    placeholder={`Title: ${generatedTitle}`}
                    className="rounded-sm p-5 text-black w-full"
                />
                <input
                    type="text"
                    name="description"
                    value={newEvent.description}
                    onChange={handleInputChange}
                    placeholder={`Description: ${generatedDescription}`}
                    className="rounded-sm p-5 text-black w-full"
                />
                <div className="flex justify-between gap-2 w-full">
                    <div>
                        <p> Start date: </p>
                        <input
                            type="date"
                            name="startDate"
                            value={newEvent.startDate}
                            onChange={handleInputChange}
                            placeholder="Start Date"
                            className="rounded-sm p-5 text-black"
                        />
                    </div>
                    <div>
                        <p> End date: </p>
                        <input
                            type="date"
                            name="endDate"
                            value={newEvent.endDate}
                            onChange={handleInputChange}
                            placeholder="End Date"
                            className="rounded-sm p-5 text-black"
                            />
                    </div>
                </div>
                <div className="flex justify-between gap-2 w-full">
                <div>
                    <p> Start time: </p>
                    <input
                        type="time"
                        name="startHour"
                        value={newEvent.startHour}
                        onChange={handleInputChange}
                        placeholder="Start Hour"
                        className="rounded-sm p-5 text-black"
                        />
                </div>
              
[truncated — 825 more characters]
```

### app/signup/[[...signup]]/page.tsx

```typescript
import { SignUp } from "@clerk/nextjs";
import { neobrutalism } from "@clerk/themes";
import Image from "next/image";

export default function Signup() {

  return (
    <div className="w-full h-full flex flex-col justify-center items-center">
      <SignUp appearance={{
          baseTheme: neobrutalism,
          variables: {
            colorBackground: "#ffdab5"
          }
        }}/>
    </div>
  );
}
```

### app/signin/[[...signin]]/page.tsx

```typescript
import { SignIn } from "@clerk/nextjs";
import { neobrutalism } from "@clerk/themes";
import Image from "next/image";

export default function Signin() {

  return (
    <div className="w-full h-full flex flex-col justify-center items-center">
      <SignIn appearance={{
          baseTheme: neobrutalism,
          variables: {
            colorBackground: "#ffdab5"
          }
        }}/>
    </div>
  );
}

```

### app/home/create/page.tsx

```typescript
"use client"
import { useRouter } from "next/navigation";
import { Courier_Prime } from "next/font/google";
import { useUser } from "@clerk/clerk-react";
import Image from "next/image";


import axios from "axios";

import { useEffect, useRef, useState } from "react";

import { FaCopy } from "react-icons/fa6";

const courierPrime = Courier_Prime({
  subsets: ["latin"],
  weight: "400",
  display: "swap"
});

export default function Create() {
  const router = useRouter();
  const nameRef = useRef(null);
  const { user, isLoaded } = useUser();

  const [famCreate, setFamCreate] = useState(false);
  const [familyID, setfamilyID] = useState("");
  const [copySuccess, setCopySuccess] = useState('');

  const copyClick = async () => {
    try {
      await navigator.clipboard.writeText(`${familyID}`);
      setCopySuccess('Copied');
      setTimeout(() => setCopySuccess(''), 2000);
    } catch (err) {
      setCopySuccess('Failed');
    }
  };

  const onCreate = async () => {
    if (nameRef.current.value && isLoaded) {
      try {
        const familyResponse = await axios.post(`${process.env.NEXT_PUBLIC_API}/family`, {
          userId: user?.id,
          name: nameRef.current.value,
        });

        console.log('SUCCESS family post', JSON.parse(familyResponse.data.body));

        const famId = JSON.parse(familyResponse.data.body).familyId;

        setfamilyID(famId);
        setFamCreate(true);

        router.push('/home');

      } catch (err) {
        console.error('ERROR', err);
      }
    }
  };

  return (
    <div className="w-screen h-screen">
    <div className="w-full h-full flex flex-col justify-center items-center">

      {famCreate ?
      <div className="w-full h-full flex flex-col justify-center items-center">
        <Image src="/happy.png" alt="happy" width="400" height="400" className="animate-fade animate-delay-1000 animate-ease-in" />
        <h1 className="text-5xl drop-shadow-sm animate-fade-up animate-delay-700"> Family Created! </h1>
        <h2 className="text-l drop-shadow-sm mt-4 animate-fade-up animate-delay-900"> Your Family ID is: </h2>
        <h2 className="font-bold underline whitespace-nowrap mt-[1px]"> {familyID} </h2>
        <div className="flex gap-8 flex-row">
        <button onClick = {() => {router.push('/home')}} className="mt-4 text-white bg-gradient-to-r from-orange-400 via-orange-500 to-orange-600 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 mb-2"> Next </button>
        <button onClick={copyClick} className=" mt-4 text-gray-900 bg-gradient-to-r from-lime-200 via-lime-400 to-lime-500 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-lime-300 dark:focus:ring-lime-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 mb-2"> Copy ID </button>
        </div>
      </div>
      :
      <>
      <h1 className="text-5xl drop-shadow-sm"> Create a Family! </h1>
      <h2 className="text-xl drop-shadow-sm mt-3"> What's your family name? </h2>
      <input ref={nameRef} placeholder="family name..." className={`mt-1 text-center rounded-xl text-black pt-1 pb-1 w-64 ${courierPrime.className}`}></input>
      <button onClick = {onCreate} className=" mt-4 bg-transparent/20 hover:bg-transparent/40 transition-colors rounded shadow px-14 py-2">
        Next
      </button>
      </>
      }
    </div>
    </div>
  )
}


  // const onCreate = () => {
  //   if (nameRef.current.value) {
  //     axios.post(`${process.env.NEXT_PUBLIC_API}/family`, {
  //       userId: user?.id,
  //       name: nameRef.current.value
  //     })
  //     .then(res => {
  //       let id = JSON.parse(res.data.body).familyId;
  //       console.log('SUCCESS family post', id);

  //       axios.put(`${process.env.NEXT_PUBLIC_API}/user/family`, {
  //         userId: user?.id,
  //         familyId: id
  //       })
  //       .then(res => {
  //         console.log('SUCCESS linking user to family', res);
  //         router.push('/home');
  //       })
  //       .catch(err => {
  //         console.log('ERROR linking user to family', err);
  //       })

  //     })
  //     .catch(err => {
  //       console.log('ERROR family post', err);
  //     })
  //   }
  // }
```

### middleware.ts

```typescript
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware()

export const config = {
  matcher: [
    // Skip Next.js internals and all static files, unless found in search params
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
}
```

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