From 06638e6e3937cf068586cab60204b1a4fdafac9c Mon Sep 17 00:00:00 2001
From: Nishant Jain <89480234+Nishantjain10@users.noreply.github.com>
Date: Fri, 20 Jun 2025 08:32:40 +0000
Subject: [PATCH 1/4] fix: correct position field attributes, add env config,
and update readme file
---
react/formspree/.env.example | 11 ++++
react/formspree/.gitignore | 4 ++
react/formspree/README.md | 106 ++++++++++++++++++++++++++++++++---
react/formspree/src/App.jsx | 8 +--
4 files changed, 118 insertions(+), 11 deletions(-)
create mode 100644 react/formspree/.env.example
diff --git a/react/formspree/.env.example b/react/formspree/.env.example
new file mode 100644
index 0000000..62ecaa0
--- /dev/null
+++ b/react/formspree/.env.example
@@ -0,0 +1,11 @@
+# Formspree configuration
+# Replace 'xxxxxxxxxxxx' with your actual form ID from formspree.io
+VITE_FORMSPREE_FORM_ID=xxxxxxxxxxxx
+
+# Example:
+# VITE_FORMSPREE_FORM_ID=xrgkpqld
+
+# Instructions:
+# 1. Copy this file and rename it to '.env'
+# 2. Replace the placeholder value with your actual Formspree form ID
+# 4. Restart your development server after making changes to .env
\ No newline at end of file
diff --git a/react/formspree/.gitignore b/react/formspree/.gitignore
index 3c390ac..7dc0276 100644
--- a/react/formspree/.gitignore
+++ b/react/formspree/.gitignore
@@ -22,3 +22,7 @@ dist-ssr
*.njsproj
*.sln
*.sw?
+
+.env
+.env.local
+.env.*.local
\ No newline at end of file
diff --git a/react/formspree/README.md b/react/formspree/README.md
index 7059a96..906fd7e 100644
--- a/react/formspree/README.md
+++ b/react/formspree/README.md
@@ -1,12 +1,104 @@
-# React + Vite
+# Job Application Form with Formspree
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+A modern, responsive job application form built with React, Vite, and Tailwind CSS, integrated with Formspree for form submissions.
-Currently, two official plugins are available:
+## Features
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+- 📝 Clean and professional job application form
+- ⚡ Built with Vite for fast development
+- 🔒 Secure form submissions via Formspree
+- ✨ Real-time form validation
-## Expanding the ESLint configuration
+## Prerequisites
-If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
+Before you begin, ensure you have the following installed:
+- Node.js (v14 or higher)
+- npm or yarn
+- A Formspree account and form ID
+
+## Quick Start
+
+1. Clone the repository:
+```bash
+git clone https://github.com/yourusername/formspree-job-application-form.git
+cd formspree-job-application-form
+```
+
+2. Install dependencies:
+```bash
+npm install
+# or
+yarn install
+```
+
+3. Configure environment variables:
+ - Copy the example environment file:
+ ```bash
+ cp env.example .env
+ ```
+ - Update the `.env` file with your Formspree form ID:
+ ```env
+ VITE_FORMSPREE_FORM_ID=your_form_id_here
+ ```
+
+4. Start the development server:
+```bash
+npm run dev
+# or
+yarn dev
+```
+
+5. Open your browser and visit `http://localhost:5173`
+
+## Environment Variables
+
+The following environment variables are required:
+
+| Variable | Description | Example |
+|----------|-------------|---------|
+| VITE_FORMSPREE_FORM_ID | Your Formspree form ID | xrgkpqld |
+
+## Project Structure
+
+```
+formspree-job-application-form/
+├── src/
+│ ├── App.jsx # Main application component
+│ ├── App.css # Application styles
+│ ├── main.jsx # Entry point
+│ └── assets/ # Static assets
+├── public/ # Public assets
+├── .env # Environment variables (not in git)
+├── env.example # Example environment variables
+├── package.json # Project dependencies
+└── README.md # Project documentation
+```
+
+## Development
+
+### Available Scripts
+
+- `npm run dev` - Start development server
+- `npm run build` - Build for production
+- `npm run preview` - Preview production build
+- `npm run lint` - Run ESLint
+- `npm run format` - Format code with Prettier
+
+## Contributing
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/amazing-feature`)
+3. Commit your changes (`git commit -m 'Add some amazing feature'`)
+4. Push to the branch (`git push origin feature/amazing-feature`)
+5. Open a Pull Request
+
+## License
+
+This project is licensed under the MIT License
+
+## Acknowledgments
+
+- [React](https://reactjs.org/)
+- [Vite](https://vitejs.dev/)
+- [Tailwind CSS](https://tailwindcss.com/)
+- [Formspree](https://formspree.io/)
diff --git a/react/formspree/src/App.jsx b/react/formspree/src/App.jsx
index 43f24c8..96ae0fc 100644
--- a/react/formspree/src/App.jsx
+++ b/react/formspree/src/App.jsx
@@ -3,7 +3,7 @@ import './App.css'
import { useForm, ValidationError } from "@formspree/react";
function App() {
- const [state, handleSubmit] = useForm("FORM_ID");
+ const [state, handleSubmit] = useForm(import.meta.env.VITE_FORMSPREE_FORM_ID);
if (state.succeeded) {
return (
@@ -223,13 +223,13 @@ function App() {
-
+
Position
Software Engineer
Senior Software Engineer
From 8ce614b0439a5ea3e69c2e5cfc9ab1393e363f98 Mon Sep 17 00:00:00 2001
From: Nishant Jain <89480234+Nishantjain10@users.noreply.github.com>
Date: Fri, 20 Jun 2025 09:17:57 +0000
Subject: [PATCH 2/4] fix: restructured and updated readme with new env configs
---
react/react-admin/README.md | 127 ++++++++++++++++++++++++++++++------
1 file changed, 108 insertions(+), 19 deletions(-)
diff --git a/react/react-admin/README.md b/react/react-admin/README.md
index e3e3638..e3ed839 100644
--- a/react/react-admin/README.md
+++ b/react/react-admin/README.md
@@ -1,33 +1,122 @@
-# React-admin Demo With AppWrite
+# React-admin Demo With Appwrite
-This is a demo of the [AppWrite](https://appwrite.io/) adapter for [react-admin](https://github.com/marmelab/react-admin).
+This is a demo of the [Appwrite](https://appwrite.io/) adapter for [react-admin](https://github.com/marmelab/react-admin), a frontend framework for building B2B applications on top of REST/GraphQL APIs.
-To explore the source code, start with [src/App.tsx](https://github.com/marmelab/ra-appwrite/blob/main/packages/demo/src/App.tsx).
+## Features
-## Requirements
+- ⚡ A complete admin dashboard built with React-admin
+- 💿 Backed by an [Appwrite](https://appwrite.io/) backend
+- ⚙️ Automatic database, collection, and user seeding
+- 🎨 Rich UI components from Material-UI
-To run this demo, you must have configured an **Appwrite project**. You can either use an existing project or create a new one.
+## Prerequisites
-This project comes with a script that will create the necessary **database**, **collections** and **users** for you. This script will be run against the Appwrite project you choose in the `.env.local` file.
+Before you begin, ensure you have the following installed:
+- Node.js (v18 or higher recommended)
+- npm or yarn
+- An Appwrite project
-## How to run
+## Quick Start
-Clone the `ra-appwrite` repository, then copy the `packages/demo/.env.local-example` file to `packages/demo/.env.local` and fill in the appwrite endpoint, project id and API key to use.
+1. Clone the repository:
+```bash
+git clone https://github.com/marmelab/ra-appwrite.git
+cd ra-appwrite/packages/demo
+```
+
+2. Install dependencies:
+```bash
+npm install
+# or
+yarn install
+```
+
+3. Configure environment variables:
+ - Create a `.env.local` file in the `packages/demo` directory.
+ - Add the following environment variables to your `.env.local` file:
+ ```env
+ APPWRITE_SITE_API_ENDPOINT=https://cloud.appwrite.io/v1
+ APPWRITE_SITE_PROJECT_ID=your_project_id_here
+ APPWRITE_SITE_STANDARD_KEY=your_api_key_here
+ ```
+ > To create an API key, go to your Appwrite console, navigate to your project, then "API Keys". Create a new key with `users` and `databases` scopes.
+
+4. Seed the database:
+This command will create the necessary database, collections, and a demo user (`john.doe@marmelab.com`, password: `changeme`).
+```bash
+npm run db-seed
+```
+
+5. Start the development server:
+```bash
+npm run start
+# or
+yarn start
+```
-> To create an API key, go to your Appwrite console, navigate to your project, then "Overview". Scroll down to the "API Keys" section and create a new key with the `users` and `database` scopes.
+Your admin panel will be available at `http://localhost:8000`.
-Then run the following commands at the root of the repository:
+## Environment Variables
-```sh
-# Install dependencies
-make install
+The following environment variables are required:
-# Build the packages
-make build
+| Variable | Description | Example |
+|----------|-------------|---------|
+| APPWRITE_SITE_API_ENDPOINT | Your Appwrite project endpoint. | `https://cloud.appwrite.io/v1` |
+| APPWRITE_SITE_PROJECT_ID | Your Appwrite project ID. | `60b8...` |
+| APPWRITE_SITE_STANDARD_KEY | Your Appwrite project API key. | `a0b1...` |
-# Create the database, collections and users
-make db-seed
-# Start the demo app
-make run
+## Project Structure
+
+```
+react-admin/
+├── src/
+│ ├── App.tsx # Main application component
+│ ├── dashboard/ # Dashboard components
+│ ├── products/ # Product management views
+│ ├── categories/ # Category management views
+│ ├── visitors/ # Customer management views
+│ ├── orders/ # Order management views
+│ ├── invoices/ # Invoice management views
+│ ├── reviews/ # Review management views
+│ ├── layout/ # App layout components
+│ ├── themes/ # Custom themes
+│ └── ...
+├── public/ # Public assets
+├── .env.local # Environment variables (not in git)
+├── setup.ts # Database seeding script
+├── package.json # Project dependencies
+└── README.md # Project documentation
```
+
+## Available Scripts
+
+- `npm run start` - Start development server at `http://localhost:8000`
+- `npm run serve` - Preview production build
+- `npm run build` - Build for production
+- `npm run test` - Run tests
+- `npm run lint` - Run ESLint
+- `npm run db-seed` - Seed the Appwrite database
+
+## Contributing
+
+Contributions are welcome! Please follow these steps:
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/amazing-feature`)
+3. Commit your changes (`git commit -m 'Add some amazing feature'`)
+4. Push to the branch (`git push origin feature/amazing-feature`)
+5. Open a Pull Request
+
+## License
+
+This project is licensed under the MIT License.
+
+## Acknowledgments
+
+- [React](https://reactjs.org/)
+- [Vite](https://vitejs.dev/)
+- [React-admin](https://marmelab.com/react-admin/)
+- [Appwrite](https://appwrite.io/)
+- [Material-UI](https://mui.com/)
From 895da2c1d160d5a67bd56c7f96137e381061857d Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Kaiser
Date: Fri, 20 Jun 2025 14:10:46 +0200
Subject: [PATCH 3/4] fix project config and readme
---
react/react-admin/.env | 4 +-
react/react-admin/README.md | 49 ++--
react/react-admin/setup.ts | 516 ++++++++++++++++++------------------
3 files changed, 281 insertions(+), 288 deletions(-)
diff --git a/react/react-admin/.env b/react/react-admin/.env
index 5eb4d1f..73f6585 100644
--- a/react/react-admin/.env
+++ b/react/react-admin/.env
@@ -1,4 +1,4 @@
-VITE_APPWRITE_ENDPOINT=${VITE_APPWRITE_ENDPOINT}
-VITE_APPWRITE_PROJECT_ID=${VITE_APPWRITE_PROJECT_ID}
+VITE_APPWRITE_ENDPOINT=${APPWRITE_SITE_API_ENDPOINT}
+VITE_APPWRITE_PROJECT_ID=${APPWRITE_SITE_PROJECT_ID}
VITE_APPWRITE_DATABASE_ID=admin
VITE_APPWRITE_COLLECTION_IDS='{"reviews":"reviews","invoices":"invoices","orders":"orders","products":"products","categories":"categories","customers":"customers"}'
diff --git a/react/react-admin/README.md b/react/react-admin/README.md
index e3ed839..4b94a0d 100644
--- a/react/react-admin/README.md
+++ b/react/react-admin/README.md
@@ -4,7 +4,7 @@ This is a demo of the [Appwrite](https://appwrite.io/) adapter for [react-admin]
## Features
-- ⚡ A complete admin dashboard built with React-admin
+- ⚡ A complete admin dashboard built with [React-admin](https://marmelab.com/react-admin/)
- 💿 Backed by an [Appwrite](https://appwrite.io/) backend
- ⚙️ Automatic database, collection, and user seeding
- 🎨 Rich UI components from Material-UI
@@ -19,20 +19,20 @@ Before you begin, ensure you have the following installed:
## Quick Start
1. Clone the repository:
-```bash
-git clone https://github.com/marmelab/ra-appwrite.git
-cd ra-appwrite/packages/demo
-```
+ ```bash
+ git clone https://github.com/appwrite/templates-for-sites.git
+ cd react/react-admin
+ ```
2. Install dependencies:
-```bash
-npm install
-# or
-yarn install
-```
+ ```bash
+ npm install
+ # or
+ yarn install
+ ```
3. Configure environment variables:
- - Create a `.env.local` file in the `packages/demo` directory.
+ - Create a `.env.local` file in the `react/react-admin` directory.
- Add the following environment variables to your `.env.local` file:
```env
APPWRITE_SITE_API_ENDPOINT=https://cloud.appwrite.io/v1
@@ -42,17 +42,17 @@ yarn install
> To create an API key, go to your Appwrite console, navigate to your project, then "API Keys". Create a new key with `users` and `databases` scopes.
4. Seed the database:
-This command will create the necessary database, collections, and a demo user (`john.doe@marmelab.com`, password: `changeme`).
-```bash
-npm run db-seed
-```
+ This command will create the necessary database, collections, and a demo user (`john.doe@marmelab.com`, password: `changeme`).
+ ```bash
+ npm run db-seed
+ ```
5. Start the development server:
-```bash
-npm run start
-# or
-yarn start
-```
+ ```bash
+ npm run start
+ # or
+ yarn start
+ ```
Your admin panel will be available at `http://localhost:8000`.
@@ -60,11 +60,11 @@ Your admin panel will be available at `http://localhost:8000`.
The following environment variables are required:
-| Variable | Description | Example |
-|----------|-------------|---------|
+| Variable | Description | Example |
+| -------------------------- | ------------------------------- | ------------------------------ |
| APPWRITE_SITE_API_ENDPOINT | Your Appwrite project endpoint. | `https://cloud.appwrite.io/v1` |
-| APPWRITE_SITE_PROJECT_ID | Your Appwrite project ID. | `60b8...` |
-| APPWRITE_SITE_STANDARD_KEY | Your Appwrite project API key. | `a0b1...` |
+| APPWRITE_SITE_PROJECT_ID | Your Appwrite project ID. | `60b8...` |
+| APPWRITE_SITE_STANDARD_KEY | Your Appwrite project API key. | `a0b1...` |
## Project Structure
@@ -95,7 +95,6 @@ react-admin/
- `npm run start` - Start development server at `http://localhost:8000`
- `npm run serve` - Preview production build
- `npm run build` - Build for production
-- `npm run test` - Run tests
- `npm run lint` - Run ESLint
- `npm run db-seed` - Seed the Appwrite database
diff --git a/react/react-admin/setup.ts b/react/react-admin/setup.ts
index b115d5c..a4a2a13 100644
--- a/react/react-admin/setup.ts
+++ b/react/react-admin/setup.ts
@@ -1,325 +1,319 @@
-import generateData from 'data-generator-retail';
-import * as appwrite from 'node-appwrite';
+import generateData from "data-generator-retail";
+import * as appwrite from "node-appwrite";
import {
- ID,
- Permission,
- Role,
- Query,
- RelationshipType,
- RelationMutate,
-} from 'node-appwrite';
-import dotenv from 'dotenv';
-import path from 'path';
+ ID,
+ Permission,
+ Role,
+ Query,
+ RelationshipType,
+ RelationMutate,
+} from "node-appwrite";
+import dotenv from "dotenv";
+import path from "path";
const MAX_ERRORS = 5;
-const forceSeed = process.argv.includes('--force');
+const forceSeed = process.argv.includes("--force");
-dotenv.config({ path: path.resolve(process.cwd(), '.env.local') });
+dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });
-if (!process.env.VITE_APPWRITE_ENDPOINT) {
- throw new Error(
- 'VITE_APPWRITE_ENDPOINT environment variable is not set.'
- );
+if (!process.env.APPWRITE_SITE_API_ENDPOINT) {
+ throw new Error(
+ "APPWRITE_SITE_API_ENDPOINT environment variable is not set."
+ );
}
-if (!process.env.VITE_APPWRITE_PROJECT_ID) {
- throw new Error(
- 'VITE_APPWRITE_PROJECT_ID environment variable is not set.'
- );
+if (!process.env.APPWRITE_SITE_PROJECT_ID) {
+ throw new Error("APPWRITE_SITE_PROJECT_ID environment variable is not set.");
}
-if (!process.env.VITE_APPWRITE_STANDARD_KEY) {
- throw new Error(
- 'VITE_APPWRITE_STANDARD_KEY environment variable is not set.'
- );
+if (!process.env.APPWRITE_SITE_STANDARD_KEY) {
+ throw new Error(
+ "APPWRITE_SITE_STANDARD_KEY environment variable is not set."
+ );
}
const client = new appwrite.Client()
- .setEndpoint(process.env.VITE_APPWRITE_ENDPOINT)
- .setProject(process.env.VITE_APPWRITE_PROJECT_ID)
- .setKey(process.env.VITE_APPWRITE_STANDARD_KEY);
+ .setEndpoint(process.env.APPWRITE_SITE_API_ENDPOINT)
+ .setProject(process.env.APPWRITE_SITE_PROJECT_ID)
+ .setKey(process.env.APPWRITE_SITE_STANDARD_KEY);
const users = new appwrite.Users(client);
let user;
try {
- user = await users.get('johndoe');
+ user = await users.get("johndoe");
} catch {}
if (user) {
- if (forceSeed) {
- console.log(
- 'User "john.doe@marmelab.com" already exists. Deleting user...'
- );
- await users.delete('johndoe');
- } else {
- console.log(
- 'User "john.doe@marmelab.com" already exists. Use --force to recreate it.'
- );
- console.log('Exiting.');
- process.exit(0);
- }
+ if (forceSeed) {
+ console.log(
+ 'User "john.doe@marmelab.com" already exists. Deleting user...'
+ );
+ await users.delete("johndoe");
+ } else {
+ console.log(
+ 'User "john.doe@marmelab.com" already exists. Use --force to recreate it.'
+ );
+ console.log("Exiting.");
+ process.exit(0);
+ }
}
console.log('Creating user "john.doe@marmelab.com"...');
await users.create(
- 'johndoe',
- 'john.doe@marmelab.com',
- undefined,
- 'changeme',
- 'John Doe'
+ "johndoe",
+ "john.doe@marmelab.com",
+ undefined,
+ "changeme",
+ "John Doe"
);
const databases = new appwrite.Databases(client);
-const result = await databases.list([Query.equal('name', ['admin'])]);
+const result = await databases.list([Query.equal("name", ["admin"])]);
if (result.total > 0) {
- if (forceSeed) {
- console.log('Database "admin" already exists. Deleting database...');
- await databases.delete('admin');
- } else {
- console.log(
- 'Database "admin" already exists. Use --force to recreate it.'
- );
- console.log('Exiting.');
- process.exit(0);
- }
+ if (forceSeed) {
+ console.log('Database "admin" already exists. Deleting database...');
+ await databases.delete("admin");
+ } else {
+ console.log('Database "admin" already exists. Use --force to recreate it.');
+ console.log("Exiting.");
+ process.exit(0);
+ }
}
console.log('Creating database "admin"...');
-await databases.create('admin', 'admin');
+await databases.create("admin", "admin");
const collections = [
- 'baskets',
- 'orders',
- 'customers',
- 'categories',
- 'products',
- 'invoices',
- 'reviews',
+ "baskets",
+ "orders",
+ "customers",
+ "categories",
+ "products",
+ "invoices",
+ "reviews",
] as const;
type CollectionName = (typeof collections)[number];
type Attribute = {
- key: string;
- type: 'string' | 'integer' | 'float' | 'boolean' | 'date';
- size?: number;
- required?: boolean;
- array?: boolean;
+ key: string;
+ type: "string" | "integer" | "float" | "boolean" | "date";
+ size?: number;
+ required?: boolean;
+ array?: boolean;
};
const collectionTypes: Record = {
- baskets: [
- { key: 'product_id', type: 'integer' },
- { key: 'quantity', type: 'integer' },
- ],
- customers: [
- { key: 'id', type: 'integer', required: true },
- { key: 'first_name', type: 'string', size: 100 },
- { key: 'last_name', type: 'string', size: 100 },
- { key: 'email', type: 'string', size: 100 },
- { key: 'address', type: 'string', size: 100 },
- { key: 'zipcode', type: 'string', size: 100 },
- { key: 'city', type: 'string', size: 100 },
- { key: 'stateAbbr', type: 'string', size: 100 },
- { key: 'avatar', type: 'string', size: 100 },
- { key: 'birthday', type: 'string', size: 100, required: false },
- { key: 'first_seen', type: 'date' },
- { key: 'last_seen', type: 'date' },
- { key: 'has_ordered', type: 'boolean' },
- { key: 'latest_purchase', type: 'date' },
- { key: 'has_newsletter', type: 'boolean' },
- {
- key: 'groups',
- type: 'string',
- size: 100,
- array: true,
- },
- { key: 'nb_orders', type: 'integer' },
- { key: 'total_spent', type: 'float' },
- ],
- categories: [
- { key: 'id', type: 'integer', required: true },
- { key: 'name', type: 'string', size: 100, required: true },
- ],
- products: [
- { key: 'id', type: 'integer', required: true },
- { key: 'category_id', type: 'integer' },
- { key: 'reference', type: 'string', size: 100, required: true },
- { key: 'width', type: 'float' },
- { key: 'height', type: 'float' },
- { key: 'price', type: 'float' },
- { key: 'thumbnail', type: 'string', size: 100 },
- { key: 'image', type: 'string', size: 100 },
- { key: 'description', type: 'string', size: 5000 },
- { key: 'stock', type: 'integer' },
- { key: 'sales', type: 'float' },
- ],
- orders: [
- { key: 'id', type: 'integer', required: true },
- { key: 'reference', type: 'string', size: 100, required: true },
- { key: 'date', type: 'date' },
- { key: 'customer_id', type: 'integer' },
- { key: 'total_ex_taxes', type: 'float' },
- { key: 'delivery_fees', type: 'float' },
- { key: 'tax_rate', type: 'float' },
- { key: 'taxes', type: 'float' },
- { key: 'total', type: 'float' },
- { key: 'status', type: 'string', size: 100 },
- { key: 'returned', type: 'boolean' },
- ],
- invoices: [
- { key: 'id', type: 'integer', required: true },
- { key: 'date', type: 'date' },
- { key: 'order_id', type: 'integer' },
- { key: 'customer_id', type: 'integer' },
- { key: 'total_ex_taxes', type: 'float' },
- { key: 'delivery_fees', type: 'float' },
- { key: 'tax_rate', type: 'float' },
- { key: 'taxes', type: 'float' },
- { key: 'total', type: 'float' },
- ],
- reviews: [
- { key: 'id', type: 'integer', required: true },
- { key: 'date', type: 'date' },
- { key: 'status', type: 'string', size: 100 },
- { key: 'order_id', type: 'integer' },
- { key: 'product_id', type: 'integer' },
- { key: 'customer_id', type: 'integer' },
- { key: 'rating', type: 'integer' },
- { key: 'comment', type: 'string', size: 2000 },
- ],
+ baskets: [
+ { key: "product_id", type: "integer" },
+ { key: "quantity", type: "integer" },
+ ],
+ customers: [
+ { key: "id", type: "integer", required: true },
+ { key: "first_name", type: "string", size: 100 },
+ { key: "last_name", type: "string", size: 100 },
+ { key: "email", type: "string", size: 100 },
+ { key: "address", type: "string", size: 100 },
+ { key: "zipcode", type: "string", size: 100 },
+ { key: "city", type: "string", size: 100 },
+ { key: "stateAbbr", type: "string", size: 100 },
+ { key: "avatar", type: "string", size: 100 },
+ { key: "birthday", type: "string", size: 100, required: false },
+ { key: "first_seen", type: "date" },
+ { key: "last_seen", type: "date" },
+ { key: "has_ordered", type: "boolean" },
+ { key: "latest_purchase", type: "date" },
+ { key: "has_newsletter", type: "boolean" },
+ {
+ key: "groups",
+ type: "string",
+ size: 100,
+ array: true,
+ },
+ { key: "nb_orders", type: "integer" },
+ { key: "total_spent", type: "float" },
+ ],
+ categories: [
+ { key: "id", type: "integer", required: true },
+ { key: "name", type: "string", size: 100, required: true },
+ ],
+ products: [
+ { key: "id", type: "integer", required: true },
+ { key: "category_id", type: "integer" },
+ { key: "reference", type: "string", size: 100, required: true },
+ { key: "width", type: "float" },
+ { key: "height", type: "float" },
+ { key: "price", type: "float" },
+ { key: "thumbnail", type: "string", size: 100 },
+ { key: "image", type: "string", size: 100 },
+ { key: "description", type: "string", size: 5000 },
+ { key: "stock", type: "integer" },
+ { key: "sales", type: "float" },
+ ],
+ orders: [
+ { key: "id", type: "integer", required: true },
+ { key: "reference", type: "string", size: 100, required: true },
+ { key: "date", type: "date" },
+ { key: "customer_id", type: "integer" },
+ { key: "total_ex_taxes", type: "float" },
+ { key: "delivery_fees", type: "float" },
+ { key: "tax_rate", type: "float" },
+ { key: "taxes", type: "float" },
+ { key: "total", type: "float" },
+ { key: "status", type: "string", size: 100 },
+ { key: "returned", type: "boolean" },
+ ],
+ invoices: [
+ { key: "id", type: "integer", required: true },
+ { key: "date", type: "date" },
+ { key: "order_id", type: "integer" },
+ { key: "customer_id", type: "integer" },
+ { key: "total_ex_taxes", type: "float" },
+ { key: "delivery_fees", type: "float" },
+ { key: "tax_rate", type: "float" },
+ { key: "taxes", type: "float" },
+ { key: "total", type: "float" },
+ ],
+ reviews: [
+ { key: "id", type: "integer", required: true },
+ { key: "date", type: "date" },
+ { key: "status", type: "string", size: 100 },
+ { key: "order_id", type: "integer" },
+ { key: "product_id", type: "integer" },
+ { key: "customer_id", type: "integer" },
+ { key: "rating", type: "integer" },
+ { key: "comment", type: "string", size: 2000 },
+ ],
};
for (const collectionName of collections) {
- console.log(`Creating collection "${collectionName}"...`);
- await databases.createCollection('admin', collectionName, collectionName, [
- Permission.read(Role.users()),
- Permission.write(Role.users()),
- Permission.update(Role.users()),
- Permission.delete(Role.users()),
- ]);
+ console.log(`Creating collection "${collectionName}"...`);
+ await databases.createCollection("admin", collectionName, collectionName, [
+ Permission.read(Role.users()),
+ Permission.write(Role.users()),
+ Permission.update(Role.users()),
+ Permission.delete(Role.users()),
+ ]);
}
for (const [collectionName, attributes] of Object.entries(collectionTypes)) {
- console.log(`Creating attributes for collection "${collectionName}"...`);
- for (const attribute of attributes) {
- switch (attribute.type) {
- case 'string':
- await databases.createStringAttribute(
- 'admin',
- collectionName,
- attribute.key,
- attribute.size || 255,
- attribute.required || false,
- undefined,
- attribute.array || false
- );
- break;
- case 'integer':
- await databases.createIntegerAttribute(
- 'admin',
- collectionName,
- attribute.key,
- attribute.required || false,
- undefined,
- undefined,
- undefined,
- attribute.array || false
- );
- break;
- case 'float':
- await databases.createFloatAttribute(
- 'admin',
- collectionName,
- attribute.key,
- attribute.required || false,
- undefined,
- undefined,
- undefined,
- attribute.array || false
- );
- break;
- case 'boolean':
- await databases.createBooleanAttribute(
- 'admin',
- collectionName,
- attribute.key,
- attribute.required || false,
- undefined,
- attribute.array || false
- );
- break;
- case 'date':
- await databases.createDatetimeAttribute(
- 'admin',
- collectionName,
- attribute.key,
- attribute.required || false,
- undefined,
- attribute.array || false
- );
- break;
- default:
- throw new Error(`Unknown attribute type: ${attribute.type}`);
- }
+ console.log(`Creating attributes for collection "${collectionName}"...`);
+ for (const attribute of attributes) {
+ switch (attribute.type) {
+ case "string":
+ await databases.createStringAttribute(
+ "admin",
+ collectionName,
+ attribute.key,
+ attribute.size || 255,
+ attribute.required || false,
+ undefined,
+ attribute.array || false
+ );
+ break;
+ case "integer":
+ await databases.createIntegerAttribute(
+ "admin",
+ collectionName,
+ attribute.key,
+ attribute.required || false,
+ undefined,
+ undefined,
+ undefined,
+ attribute.array || false
+ );
+ break;
+ case "float":
+ await databases.createFloatAttribute(
+ "admin",
+ collectionName,
+ attribute.key,
+ attribute.required || false,
+ undefined,
+ undefined,
+ undefined,
+ attribute.array || false
+ );
+ break;
+ case "boolean":
+ await databases.createBooleanAttribute(
+ "admin",
+ collectionName,
+ attribute.key,
+ attribute.required || false,
+ undefined,
+ attribute.array || false
+ );
+ break;
+ case "date":
+ await databases.createDatetimeAttribute(
+ "admin",
+ collectionName,
+ attribute.key,
+ attribute.required || false,
+ undefined,
+ attribute.array || false
+ );
+ break;
+ default:
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
}
+ }
}
// Special case for basket
await databases.createRelationshipAttribute(
- 'admin', // databaseId
- 'orders', // collectionId
- 'baskets', // relatedCollectionId
- RelationshipType.OneToMany, // type
- false, // twoWay (optional)
- 'basket', // key (optional)
- undefined, // twoWayKey (optional)
- RelationMutate.Cascade // onDelete (optional)
+ "admin", // databaseId
+ "orders", // collectionId
+ "baskets", // relatedCollectionId
+ RelationshipType.OneToMany, // type
+ false, // twoWay (optional)
+ "basket", // key (optional)
+ undefined, // twoWayKey (optional)
+ RelationMutate.Cascade // onDelete (optional)
);
-console.log('Generating data...');
+console.log("Generating data...");
// @ts-expect-error - Dunno why this is necessary, but the import is not recognized
const data = generateData.default();
// FIXME - Give 10 seconds for the schema to be updated
// Don't know why this is necessary, but yeah...
-await new Promise(resolve => setTimeout(resolve, 10000));
+await new Promise((resolve) => setTimeout(resolve, 10000));
let errors = 0;
for (const collectionName of collections) {
- if (collectionName === 'baskets') {
- continue;
- }
- console.log(`Inserting data into collection "${collectionName}"...`);
- for (const item of data[collectionName]) {
- try {
- await databases.createDocument(
- 'admin',
- collectionName,
- // FIXME: createDocument considers 0 to be an invalid ID
- item.id ? item.id.toString() : ID.unique(),
- item,
- [
- Permission.read(Role.users()),
- Permission.write(Role.users()),
- Permission.update(Role.users()),
- Permission.delete(Role.users()),
- ]
- );
- } catch (error) {
- console.error(
- `Error inserting item into collection "${collectionName}":`,
- { error, item }
- );
- errors++;
- if (errors >= MAX_ERRORS) {
- console.error(
- `Reached maximum error limit of ${MAX_ERRORS}. Exiting.`
- );
- process.exit(1);
- }
- }
+ if (collectionName === "baskets") {
+ continue;
+ }
+ console.log(`Inserting data into collection "${collectionName}"...`);
+ for (const item of data[collectionName]) {
+ try {
+ await databases.createDocument(
+ "admin",
+ collectionName,
+ // FIXME: createDocument considers 0 to be an invalid ID
+ item.id ? item.id.toString() : ID.unique(),
+ item,
+ [
+ Permission.read(Role.users()),
+ Permission.write(Role.users()),
+ Permission.update(Role.users()),
+ Permission.delete(Role.users()),
+ ]
+ );
+ } catch (error) {
+ console.error(
+ `Error inserting item into collection "${collectionName}":`,
+ { error, item }
+ );
+ errors++;
+ if (errors >= MAX_ERRORS) {
+ console.error(`Reached maximum error limit of ${MAX_ERRORS}. Exiting.`);
+ process.exit(1);
+ }
}
+ }
}
-console.log('Database setup completed successfully.');
+console.log("Database setup completed successfully.");
From a6feda087bc24b5c7f3e34a5674ed497d9dffd31 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Kaiser
Date: Fri, 20 Jun 2025 14:26:51 +0200
Subject: [PATCH 4/4] remove welcome banner
---
react/react-admin/src/dashboard/Dashboard.tsx | 232 +++++++++---------
react/react-admin/src/dashboard/Welcome.tsx | 74 ------
.../src/dashboard/welcome_illustration.svg | 1 -
3 files changed, 111 insertions(+), 196 deletions(-)
delete mode 100644 react/react-admin/src/dashboard/Welcome.tsx
delete mode 100644 react/react-admin/src/dashboard/welcome_illustration.svg
diff --git a/react/react-admin/src/dashboard/Dashboard.tsx b/react/react-admin/src/dashboard/Dashboard.tsx
index c258ac7..848c7a3 100644
--- a/react/react-admin/src/dashboard/Dashboard.tsx
+++ b/react/react-admin/src/dashboard/Dashboard.tsx
@@ -3,145 +3,135 @@ import { useGetList } from 'react-admin';
import { useMediaQuery, Theme } from '@mui/material';
import { subDays, startOfDay } from 'date-fns';
-import Welcome from './Welcome';
-import MonthlyRevenue from './MonthlyRevenue';
-import NbNewOrders from './NbNewOrders';
-import PendingOrders from './PendingOrders';
-import PendingReviews from './PendingReviews';
-import NewCustomers from './NewCustomers';
-import OrderChart from './OrderChart';
+import MonthlyRevenue from "./MonthlyRevenue";
+import NbNewOrders from "./NbNewOrders";
+import PendingOrders from "./PendingOrders";
+import PendingReviews from "./PendingReviews";
+import NewCustomers from "./NewCustomers";
+import OrderChart from "./OrderChart";
-import { Order } from '../types';
+import { Order } from "../types";
interface OrderStats {
- revenue: number;
- nbNewOrders: number;
- pendingOrders: Order[];
+ revenue: number;
+ nbNewOrders: number;
+ pendingOrders: Order[];
}
interface State {
- nbNewOrders?: number;
- pendingOrders?: Order[];
- recentOrders?: Order[];
- revenue?: string;
+ nbNewOrders?: number;
+ pendingOrders?: Order[];
+ recentOrders?: Order[];
+ revenue?: string;
}
const styles = {
- flex: { display: 'flex' },
- flexColumn: { display: 'flex', flexDirection: 'column' },
- leftCol: { flex: 1, marginRight: '0.5em' },
- rightCol: { flex: 1, marginLeft: '0.5em' },
- singleCol: { marginTop: '1em', marginBottom: '1em' },
+ flex: { display: "flex", marginTop: "0.5em" },
+ flexColumn: { display: "flex", flexDirection: "column", marginTop: "0.5em" },
+ leftCol: { flex: 1, marginRight: "0.5em" },
+ rightCol: { flex: 1, marginLeft: "0.5em" },
+ singleCol: { marginTop: "1em", marginBottom: "1em" },
};
-const Spacer = () => ;
-const VerticalSpacer = () => ;
+const Spacer = () => ;
+const VerticalSpacer = () => ;
const Dashboard = () => {
- const isXSmall = useMediaQuery((theme: Theme) =>
- theme.breakpoints.down('sm')
- );
- const isSmall = useMediaQuery((theme: Theme) =>
- theme.breakpoints.down('lg')
- );
- const aMonthAgo = useMemo(() => subDays(startOfDay(new Date()), 30), []);
+ const isXSmall = useMediaQuery((theme: Theme) =>
+ theme.breakpoints.down("sm")
+ );
+ const isSmall = useMediaQuery((theme: Theme) => theme.breakpoints.down("lg"));
+ const aMonthAgo = useMemo(() => subDays(startOfDay(new Date()), 30), []);
- const { data: orders } = useGetList('orders', {
- filter: { date_gte: aMonthAgo.toISOString() },
- sort: { field: 'date', order: 'DESC' },
- pagination: { page: 1, perPage: 50 },
- });
+ const { data: orders } = useGetList("orders", {
+ filter: { date_gte: aMonthAgo.toISOString() },
+ sort: { field: "date", order: "DESC" },
+ pagination: { page: 1, perPage: 50 },
+ });
- const aggregation = useMemo(() => {
- if (!orders) return {};
- const aggregations = orders
- .filter(order => order.status !== 'cancelled')
- .reduce(
- (stats: OrderStats, order) => {
- if (order.status !== 'cancelled') {
- stats.revenue += order.total;
- stats.nbNewOrders++;
- }
- if (order.status === 'ordered') {
- stats.pendingOrders.push(order);
- }
- return stats;
- },
- {
- revenue: 0,
- nbNewOrders: 0,
- pendingOrders: [],
- }
- );
- return {
- recentOrders: orders,
- revenue: aggregations.revenue.toLocaleString(undefined, {
- style: 'currency',
- currency: 'USD',
- minimumFractionDigits: 0,
- maximumFractionDigits: 0,
- }),
- nbNewOrders: aggregations.nbNewOrders,
- pendingOrders: aggregations.pendingOrders,
- };
- }, [orders]);
+ const aggregation = useMemo(() => {
+ if (!orders) return {};
+ const aggregations = orders
+ .filter((order) => order.status !== "cancelled")
+ .reduce(
+ (stats: OrderStats, order) => {
+ if (order.status !== "cancelled") {
+ stats.revenue += order.total;
+ stats.nbNewOrders++;
+ }
+ if (order.status === "ordered") {
+ stats.pendingOrders.push(order);
+ }
+ return stats;
+ },
+ {
+ revenue: 0,
+ nbNewOrders: 0,
+ pendingOrders: [],
+ }
+ );
+ return {
+ recentOrders: orders,
+ revenue: aggregations.revenue.toLocaleString(undefined, {
+ style: "currency",
+ currency: "USD",
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 0,
+ }),
+ nbNewOrders: aggregations.nbNewOrders,
+ pendingOrders: aggregations.pendingOrders,
+ };
+ }, [orders]);
- const { nbNewOrders, pendingOrders, revenue, recentOrders } = aggregation;
- return isXSmall ? (
-
-
+ const { nbNewOrders, pendingOrders, revenue, recentOrders } = aggregation;
+ return isXSmall ? (
+
+ ) : isSmall ? (
+
+ ) : (
+
+
+
+
+
+
- ) : isSmall ? (
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
- ) : (
- <>
-
-
- >
- );
+
+
+
+
+ );
};
export default Dashboard;
diff --git a/react/react-admin/src/dashboard/Welcome.tsx b/react/react-admin/src/dashboard/Welcome.tsx
deleted file mode 100644
index f48bc08..0000000
--- a/react/react-admin/src/dashboard/Welcome.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import * as React from 'react';
-import { Box, Card, CardActions, Button, Typography } from '@mui/material';
-import HomeIcon from '@mui/icons-material/Home';
-import CodeIcon from '@mui/icons-material/Code';
-import { useTranslate } from 'react-admin';
-
-import publishArticleImage from './welcome_illustration.svg';
-
-const Welcome = () => {
- const translate = useTranslate();
- return (
-
- `linear-gradient(45deg, ${theme.palette.secondary.dark} 0%, ${theme.palette.secondary.light} 50%, ${theme.palette.primary.dark} 100%)`,
- color: theme => theme.palette.primary.contrastText,
- padding: '20px',
- marginTop: 2,
- marginBottom: '1em',
- }}
- >
-
-
-
- {translate('pos.dashboard.welcome.title')}
-
-
-
- {translate('pos.dashboard.welcome.subtitle')}
-
-
-
- }
- >
- {translate('pos.dashboard.welcome.ra_button')}
-
- }
- >
- {translate('pos.dashboard.welcome.demo_button')}
-
-
-
-
-
-
- );
-};
-
-export default Welcome;
diff --git a/react/react-admin/src/dashboard/welcome_illustration.svg b/react/react-admin/src/dashboard/welcome_illustration.svg
deleted file mode 100644
index a54a602..0000000
--- a/react/react-admin/src/dashboard/welcome_illustration.svg
+++ /dev/null
@@ -1 +0,0 @@
-
work_together
\ No newline at end of file