Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage
Expand All @@ -26,6 +27,7 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
56 changes: 34 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
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).
# Invoice & Inventory Manager

## Getting Started
A modern invoice generator and inventory management system built with Next.js 15 and Supabase.

First, run the development server:
## Features

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```
- Create and manage invoices
- Track inventory with real-time stock updates
- Generate professional PDF invoices
- View invoice history
- Multi-category product management with GST support

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

You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
1. Clone the repo
2. Install dependencies:
```bash
yarn install
```

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
3. Add your Supabase credentials to `.env.local`:
```
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
```

## Learn More
4. Run the dev server:
```bash
yarn dev
```

To learn more about Next.js, take a look at the following resources:
Open [http://localhost:3000](http://localhost:3000)

- [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.
## Database Schema

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
You'll need these Supabase tables:
- `inventory` - Products (id, name, price, stock, type, gst)
- `types` - Product categories (name, cgst, sgst, gst)
- `history` - Invoice records

## Deploy on Vercel
## Stack

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.
- Next.js 15
- Supabase
- Redux Toolkit
- Tailwind CSS (via globals.css)
4 changes: 1 addition & 3 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
// Server Actions are now stable in Next.js 15
};

module.exports = nextConfig;
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bill-gen-next",
"version": "0.1.0",
"name": "invoice-inventory-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
Expand All @@ -10,14 +10,14 @@
"lint": "next lint"
},
"dependencies": {
"@headlessui/react": "^1.7.14",
"@reduxjs/toolkit": "^1.9.5",
"@supabase/auth-helpers-nextjs": "^0.7.1",
"@supabase/supabase-js": "^2.24.0",
"next": "^13.4.1",
"@headlessui/react": "^2.2.0",
"@reduxjs/toolkit": "^2.3.0",
"@supabase/ssr": "^0.5.2",
"@supabase/supabase-js": "^2.46.1",
"next": "^15.0.3",
"num-words": "^1.2.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "^8.0.7"
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-redux": "^9.1.2"
}
}
4 changes: 2 additions & 2 deletions src/app/dashboard/add.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import styles from "@/styles/page.module.css";
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import { Dialog } from "@headlessui/react";
import { useRouter } from "next/navigation";
export const revalidate = 0;
Expand All @@ -10,7 +10,7 @@ const add = () => {
const [newdata, setnewData] = useState();
const [type, setType] = useState();
const [isOpen, setIsOpen] = useState(false);
const supabase = createClientComponentClient();
const supabase = createClient();
const router = useRouter();

const handleAdd = async (e) => {
Expand Down
5 changes: 2 additions & 3 deletions src/app/dashboard/buttons.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"use client";
import { useEffect, useState } from "react";
import styles from "@/styles/page.module.css";

import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import { useRouter } from "next/navigation";

const buttons = ({ itemdata }) => {
const router = useRouter();
const [data, setData] = useState(itemdata);
const supabase = createClientComponentClient();
const supabase = createClient();

const update = async () => {
await supabase
Expand Down
8 changes: 2 additions & 6 deletions src/app/dashboard/page.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import styles from "@/styles/page.module.css";

import { cookies } from "next/headers";
import { createServerComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/server";

import Add from "./add";
import Buttons from "./buttons";
import Price from "./price";
import Type from "./type";

// optimize with redux
// import { store } from "@/redux/store";
export const revalidate = 0;

const dashboard = async () => {
const supabase = createServerComponentClient({ cookies });
const supabase = await createClient();
const { data, error } = await supabase
.from("inventory")
.select("*")
Expand Down
5 changes: 2 additions & 3 deletions src/app/dashboard/price.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"use client";
import styles from "@/styles/page.module.css";

import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import { useEffect, useState } from "react";

const price = ({ price, id }) => {
const supabase = createClientComponentClient();
const supabase = createClient();
const [data, setData] = useState(price);

const handleInput = (e) => {
Expand Down
4 changes: 2 additions & 2 deletions src/app/dashboard/type.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"use client";
import { useState } from "react";
import styles from "@/styles/page.module.css";
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import { Dialog } from "@headlessui/react";
import { useRouter } from "next/navigation";
export const revalidate = 0;

const type = () => {
const [newdata, setnewData] = useState();
const [isOpen, setIsOpen] = useState(false);
const supabase = createClientComponentClient();
const supabase = createClient();
const router = useRouter();

const handleAdd = async (e) => {
Expand Down
5 changes: 2 additions & 3 deletions src/app/history/page.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";
import styles from "@/styles/page.module.css";

import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import { useEffect, useState } from "react";

const history = () => {
Expand All @@ -10,7 +9,7 @@ const history = () => {
from: "",
to: "",
});
const supabase = createClientComponentClient();
const supabase = createClient();

const getHistory = async () => {
if (date.from === "" || date.to === "") {
Expand Down
4 changes: 2 additions & 2 deletions src/app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ const inter = Inter({
display: "swap",
});
export const metadata = {
title: "Bill Generator",
description: "Generate bills for your business",
title: "Invoice & Inventory Manager",
description: "Generate invoices and manage inventory",
};

export default function RootLayout({ children }) {
Expand Down
12 changes: 4 additions & 8 deletions src/app/login/page.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
"use client";
import { useState } from "react";
import styles from "@/styles/page.module.css";
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { useRouter } from "next/navigation";

function App() {
const [user, setUser] = useState("");
const [password, setPassword] = useState("");
const supabase = createClientComponentClient();
const router = useRouter();

const handleSubmit = async (e) => {
e.preventDefault();
const { data, error } = await supabase.auth.signInWithPassword({
email: user,
password: password,
});
if (error) console.log(error);
else router.push("/");
// Auth is disabled - login page kept for reference only
alert("Authentication is disabled. This app is now public.");
router.push("/");
};
return (
<form className={styles["form"]} onSubmit={handleSubmit}>
Expand Down
33 changes: 12 additions & 21 deletions src/app/preview/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import { useEffect, useState } from "react";
import Total from "@/components/total";
import numWords from "num-words";
import { Dialog } from "@headlessui/react";

import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { createClient } from "@/utils/supabase/client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import Image from "next/image";

import { useDispatch, useSelector } from "react-redux";
import { empty } from "@/redux/formSlice";
Expand All @@ -22,7 +20,7 @@ const preview = () => {
const tax = useSelector((state) => state.data.tax);
const router = useRouter();

const supabase = createClientComponentClient();
const supabase = createClient();
const [isOpen, setIsOpen] = useState(false);
const [invoiceno, setInvoiceno] = useState("<generating>");

Expand Down Expand Up @@ -70,8 +68,7 @@ const preview = () => {
if (error) console.log(error);
else {
dispatch(empty());
// refetch todo
document.title = "Bill Generator";
document.title = "Invoice Generator";
router.push("/");
}
};
Expand Down Expand Up @@ -103,14 +100,14 @@ const preview = () => {
<div className={styles.invoice}>
<div className={styles.left}>
<div className={styles["invoice-company-name"]}>
SARAVANAN TRADERS
YOUR COMPANY NAME
</div>
<div className={styles["invoice-company-address"]}>
No.2/32, Kakkan Nagar, 2nd Cross Street, <br />
Adambakkam, Chennai - 600088, Tamilnadu.
Your Company Address <br />
City, State - PIN Code
</div>
<div className={styles["invoice-company-contact"]}>
GSTIN: 33BAZPS2766P1ZI <br /> Email: saravanantraderss@gmail.com
GSTIN: Your GSTIN <br /> Email: your@email.com
</div>
</div>
{/* */}
Expand All @@ -119,7 +116,7 @@ const preview = () => {
Date: {new Date().toLocaleDateString("en-IN")}
</div>
<div className={styles["invoice-number"]}>
Invoice No: ST/{invoiceno}/23-24
Invoice No: INV/{invoiceno}
</div>
<div className={styles["invoice-method"]}>
Payment Method: {formData.paymed}
Expand Down Expand Up @@ -256,13 +253,13 @@ const preview = () => {
<div>
<div className={styles["right"]} style={{ width: "100%" }}>
<div className={styles["invoice-bank"]}>
Bank Name: Karur Vysya Bank
Bank Name: Your Bank Name
</div>
<div className={styles["invoice-bank"]}>
Account Number: 1104135000009692
Account Number: Your Account Number
</div>
<div className={styles["invoice-bank"]}>
Branch/IFSC Code: Alandur/KVBL00001104
Branch/IFSC Code: Your Branch/IFSC
</div>
</div>
</div>
Expand All @@ -278,14 +275,8 @@ const preview = () => {
</div>
<div className={styles["invoice-declaration-item"]}>
<div className={styles["invoice-declaration-title"]}>
For SARAVANAN TRADERS
For YOUR COMPANY NAME
<div className={styles["invoice-declaration-signature"]}>
<Image
src="/sign.png"
width={100}
height={50}
alt="Signature"
/>
Authorised Signatory
</div>
</div>
Expand Down
11 changes: 0 additions & 11 deletions src/app/supabase.jsx

This file was deleted.

Loading