140 Commits

Author SHA1 Message Date
notkshitij e3935c9760 Added confirm password text box and show/hide password toggles in both password fields. 2025-07-18 02:47:16 +05:30
notkshitij 4115193ef7 Added loader while checking whether password was leaked previously. 2025-07-18 02:40:15 +05:30
notkshitij 2afda4873b Added basic password strength indicator 2025-07-18 02:34:05 +05:30
notkshitij bc41904e06 Akcually, axios and sha1 are required in backend 🤓 2025-07-18 02:30:59 +05:30
notkshitij 4fb54705ca Removed axios and sha1 packages from backend. 2025-07-18 02:13:31 +05:30
notkshitij 12ce8b1ec3 Added axios and sha1 packages. 2025-07-18 02:13:12 +05:30
notkshitij 9c3feca6a7 feat(login): improve error handling and show rate limit message
- Display meaningful error messages on login failure, including rate limiting (429)
- Added fallback for unexpected JSON responses from the server
- Integrated `Message` component for error display
- Cleaned up form value clearing and error state management
2025-07-18 02:12:46 +05:30
notkshitij aaf88fda56 feat(signup): add password strength and breach check using HIBP API
- Implemented frontend password validation for minimum strength:
  - Requires 8+ characters with uppercase, lowercase, digit, and special character.
- Integrated haveibeenpwned (HIBP) k-anonymity API to detect breached passwords.
- Display appropriate error messages for weak or pwned passwords.
- Updated Message component to support "error" and "default" types with styling.
- Cleaned up SignupPage form UI and removed unused refs (e.g., roleElement).
- Created passwordUtils.js to isolate SHA-1 hashing and API call logic.
2025-07-18 02:06:43 +05:30
notkshitij 23a271fbce Removed package-lock.json and updated .gitignore. 2025-07-18 01:26:13 +05:30
notkshitij f3e52cda73 Added new packages and updated some existing ones. 2025-07-18 01:25:27 +05:30
notkshitij 04e69202b6 Added password policy and checking if password appeared in a breach w/ haveibeenpwed api. 2025-07-18 01:22:01 +05:30
notkshitij 001727ab85 Added helmet secure headers and HTTPS redirection. 2025-07-18 01:21:07 +05:30
notkshitij 351f57229c Apply rate limiter logic. 2025-07-18 01:18:10 +05:30
notkshitij 25cfa659c7 Added rate limiting logic in middleware. 2025-07-18 01:17:53 +05:30
notkshitij d5d1e16d1f Moved the query parameter into the correct position and added logging for the final URI for database connect. 2025-07-18 01:06:42 +05:30
notkshitij e40eae866a Merged Salvi's commit he made to master branch (0ffcd1274d659b3e5c44a4813c57eb46e6ea4bed) for fixing UI changes. 2025-06-24 13:50:01 +05:30
notkshitij 3458d21567 Added multilingual (English, Hindi, Marathi & French) in features section. 2025-06-23 20:31:13 +05:30
notkshitij 63c73bc6d9 Added guide for translation! 2025-06-23 20:22:06 +05:30
notkshitij 90d09350e2 Perfomed complete Marathi translation. Not exactly complete but up to where mr & fr was done. 2025-06-21 00:53:25 +05:30
notkshitij 06b11cb2eb Perfomed complete Hindi translation. Not exactly complete but up to where fr was done. 2025-06-21 00:51:41 +05:30
notkshitij 14295f1931 Merge branch 'main' into frontend-multilingual up to commit 0aa8a3842c 2025-06-21 00:28:12 +05:30
notkshitij 0aa8a3842c Merged models/ directory from bhakti's branch up to commit 3d79d69640 since that is the branch we used for demo during hackathon. 2025-06-21 00:22:49 +05:30
notkshitij 1395496fce Merged all changes from frontend branch w/ main branch up to commit 0d757995bb 2025-06-21 00:21:57 +05:30
notkshitij 91aaa092f3 Added package-lock.json and node_modules in global .gitignore 2025-06-21 00:20:32 +05:30
notkshitij a7ae00beac Removed package-lock.json, package.json and node_modules from root dir. Not needed. 2025-06-21 00:20:27 +05:30
KaranSalvi 7ad0db73b0 Resolved conflict by deleting multer.js and updated packages 2025-06-21 00:19:50 +05:30
notkshitij 36693ba21b Made ForgetPassword and ResetPassword multilingual. Also added en and fr translations for the same. 2025-06-20 23:28:44 +05:30
notkshitij 9e170a91ef Added translation for SignupPage.jsx along with en and fr translations. 2025-06-20 23:24:53 +05:30
notkshitij 911b08ba71 Removed unused jsx files from Home directory in src/pages. 2025-06-20 23:19:34 +05:30
notkshitij 36781b3af4 Made Testimonial.jsx multilingual. Also updated en and fr translations for the same. 2025-06-20 23:17:54 +05:30
notkshitij a70afd8615 Fixed Cards.jsx, now the homepage is not blank. Also added key:values for text in Cards.jsx 2025-06-20 23:13:22 +05:30
notkshitij 9fe5d04fca Made pages in Home/ directory multilingual:
- Cards.jsx
- Customization.jsx
- Footer.jsx
- Hero.jsx
- Hero2.jsx
- HomePage.jsx

Also added language key:values for en and fr in locales.
2025-06-20 23:12:38 +05:30
notkshitij 23e12d3c7e Support for language context in MainLoginPage.jsx
- Updated MainLoginPage component to accept a `language` prop with a default value of "en".
- Modified Navbar2 to receive the `language` prop for localization.
- Passed the `language` context to the Outlet for nested routes, enabling language-specific rendering in child components.
2025-06-19 16:29:29 +05:30
notkshitij 4b6faef5eb Replaced static text in LoginPage.jsx with translation function t(key, language). 2025-06-19 16:28:26 +05:30
notkshitij cacf3f9c0d Added language switcher function in App.jsx 2025-06-19 16:26:04 +05:30
notkshitij 697a873148 Added English (default) and French locales. This directory will store key-value pairs for translation where key will be the English word/phrase and value will be the translation of that word/phrase. 2025-06-19 16:23:35 +05:30
notkshitij c123c4985c Added service/translation.js -> Implements a translation service that dynamically loads phrases based on user language preference. 2025-06-19 16:23:35 +05:30
notkshitij 64a34fdf0d Added language switching component. This component will render a dropdown or buttons for language selection and update the language globally when changed. 2025-06-19 16:23:22 +05:30
notkshitij 5484b122a1 Added a better description in README. 2025-06-07 15:48:46 +05:30
notkshitij b2fe22195f Merged all the changes from bhakti's branch into main. 2025-04-05 18:24:23 +05:30
KaranSalvi ce864c7c55 feat: Add logs 2025-03-26 22:51:07 +05:30
KaranSalvi 407d6df417 feat:Added monitoring charts 2025-03-26 22:50:05 +05:30
KaranSalvi b961ef8fd3 feat:Fixed all the UI Pages 2025-03-26 21:31:14 +05:30
KaranSalvi aba9651c43 feat:Add individual crop page 2025-03-26 00:25:09 +05:30
KaranSalvi 0dbb68d518 feat:Add env variables file 2025-03-25 21:33:21 +05:30
KaranSalvi 262446fff7 feat: Add some new connection 2025-03-25 19:40:56 +05:30
KaranSalvi 914501036d feat: Set up RTK query for the statemanagement 2025-03-25 17:48:15 +05:30
KaranSalvi 7e204690d3 Fix: FUCK OMBAASE MESSED UP. 2025-02-23 11:38:02 +05:30
KaranSalvi ae1b2566a3 added models. 2025-02-23 11:22:34 +05:30
KaranSalvi dc0afc8d5a Changed default user profile. 2025-02-23 11:21:29 +05:30
KaranSalvi d53a4d6061 Removed navbar from dashboard. 2025-02-23 11:12:03 +05:30
KaranSalvi c839011847 Merged Ombase's changes. 2025-02-23 11:09:09 +05:30
atharvaombase 6df9befdd1 Fix:removed navbar and added space between components in dashboard 2025-02-23 11:05:12 +05:30
KaranSalvi aa97607ec4 Changed footer and testimonial. 2025-02-23 11:04:15 +05:30
atharvaombase 0048e9f462 Feat:Added Plant disease prediction 2025-02-23 10:52:31 +05:30
KaranSalvi 08fc0e790e Fixed cookie issue 2025-02-23 10:48:41 +05:30
KaranSalvi a1a0d6adc4 Made changes to honepage. 2025-02-23 10:47:58 +05:30
KaranSalvi 3aec29388b Added new icons for homepage. 2025-02-23 10:47:45 +05:30
atharvaombase dbbc0ce5f2 Feat:Added new Ai page for the Crop desies detection 2025-02-23 10:41:16 +05:30
atharvaombase 79c6c80636 Fix:Added new route for Ai 2025-02-23 10:40:40 +05:30
atharvaombase 9ac0294974 Image added 2025-02-23 10:27:07 +05:30
atharvaombase 870185001d Fix:Changed user profile 2025-02-23 10:26:41 +05:30
atharvaombase 34bdbf9f9c Fix:Fixed loader typo 2025-02-23 10:26:18 +05:30
atharvaombase a9d63abf9b Fix:Renamed this file and added the correct one
delete this file
2025-02-23 10:25:30 +05:30
atharvaombase 53b1e40d8f Fix:changed the Profile photo 2025-02-23 10:24:32 +05:30
atharvaombase c113a34f1f Fix:fixed loader typo 2025-02-23 10:23:46 +05:30
atharvaombase 9e04a4b734 Fix:fixed loader typo 2025-02-23 10:23:27 +05:30
notkshitij 3b21ab5b63 Removed useless node_modules folder and package-lock file. 2025-02-23 09:38:37 +05:30
notkshitij d431ff809e Merged frontend changes from frontend branch to main. 2025-02-23 09:37:59 +05:30
notkshitij dcc5ce361d Merged models folder from training branch. 2025-02-23 09:37:03 +05:30
notkshitij cc9c63d879 Merged bhakti's frontend changes. 2025-02-23 09:27:30 +05:30
notkshitij 4e6ce0e723 Merged Salvi's backend changes. 2025-02-23 09:26:44 +05:30
notkshitij c604fa308e Merged ombase's changes in bhakti's branch for karan to make changes to. 2025-02-23 09:16:48 +05:30
notkshitij a551e075b7 Added backend folder in Bhakti's branch for Salvi to make changes. 2025-02-23 09:15:03 +05:30
notkshitij 1966a696ab Merged backend changes made by salvi to crop controller.js 2025-02-23 09:14:01 +05:30
notkshitij 7da2809399 Added Salvi's backend folder from backend branch to allow ombase to continue testing. 2025-02-23 09:05:16 +05:30
notkshitij 3f9e6d3dee Deleted useless files such as backend, node_modules and package-lock. Modified readme. 2025-02-23 09:04:05 +05:30
notkshitij 7dd344f722 Deleted useless folders such as backend, node_modules, files such as package-lock. Also, modified readme. 2025-02-23 09:02:28 +05:30
KaranSalvi 283f62e1c2 feat:Make the server for the Prediction Model 2025-02-23 08:52:07 +05:30
Bhakti 54c7dbc940 Created component for Taking photo input for crop disease detection 2025-02-23 08:34:35 +05:30
notkshitij 4b27d1854e Added server.js for node server. References python app.py code, uses POST req. 2025-02-23 08:18:21 +05:30
notkshitij ac7ea72247 Changed the way we're specifying the path for image in app.py. Directly mention it while execting now. 2025-02-23 08:15:50 +05:30
atharvaombase 699bcb9d2c Fix:Fixed Fetch 2025-02-23 07:57:48 +05:30
atharvaombase 51eb7d8f47 still some errors 2025-02-23 07:34:46 +05:30
atharvaombase 54d90519cb Still some errors 2025-02-23 07:34:28 +05:30
atharvaombase d48736114b Feat:Added laoding animation 2025-02-23 07:34:05 +05:30
atharvaombase 36911b5701 Feat:Added loader animation 2025-02-23 07:33:20 +05:30
atharvaombase fcc52ed62a Feat:Added loader for loading animation throughout the webapp 2025-02-23 07:31:41 +05:30
atharvaombase 29e2d49ef6 Fix:Replaced Class with className 2025-02-23 07:30:54 +05:30
atharvaombase 92b647fa0e Fix:Replaced class with className 2025-02-23 07:30:14 +05:30
atharvaombase 7b2abd29b9 Fix:Replace class with className 2025-02-23 07:29:30 +05:30
atharvaombase 7f96da1555 Feat:Added Loading animation 2025-02-23 07:28:35 +05:30
atharvaombase ac723810c5 Fix:Added Create finanace and View Finance 2025-02-23 07:00:07 +05:30
Bhakti 3abcb355eb Added get started button functionality 2025-02-23 06:40:24 +05:30
Bhakti 71a951dce9 added loginbg 2025-02-23 05:43:06 +05:30
atharvaombase 04317cb9e9 Just order is changed 2025-02-23 04:45:25 +05:30
atharvaombase 7edab16bd3 Fix:Added EditFarm in the main.jsx 2025-02-23 04:44:16 +05:30
atharvaombase 86189b0f5b Feat:Added EditFarm MODAL From Flowbite for Farm deletion 2025-02-23 04:43:30 +05:30
atharvaombase 297b094de5 Fix:Changed icons and overall appearance 2025-02-23 04:42:43 +05:30
atharvaombase bcd600c766 Fix:Removed Console.log 2025-02-23 04:41:51 +05:30
atharvaombase 9293287566 Fix:Added logic to remove a crop from the database 2025-02-23 04:40:52 +05:30
atharvaombase 22533ee75d Fix:Added data for whole year instead of 5 months 2025-02-23 04:39:58 +05:30
atharvaombase f8e6efb5b3 Fix:Added EditFarm component Instead of <a> 2025-02-23 04:39:12 +05:30
atharvaombase a67e23fa6a Testing:Tested for the bakend data with console.log 2025-02-23 03:50:54 +05:30
atharvaombase 9f98ebd4c4 Fix:Added a div to keep navbar from overlapping the initial elements 2025-02-23 03:49:55 +05:30
notkshitij 1f0855c9f3 Merged all the changes from backend and frontend branch to main. Everything functional. 2025-02-23 03:38:45 +05:30
Bhakti f3d0fd7459 Merge branch 'bhakti' of https://git.kska.io/notkshitij/status200 into bhakti 2025-02-23 03:28:40 +05:30
notkshitij 0dbc742f42 Merged ombase's changes. 2025-02-23 03:25:29 +05:30
notkshitij 2be6de06d6 Merged Bhakti's changes. 2025-02-23 03:24:24 +05:30
atharvaombase 5cde4a3b45 Fix:Improved CSS of the side bar 2025-02-23 03:24:09 +05:30
notkshitij 228ce106b2 Merged Omabse's changes. 2025-02-23 03:23:20 +05:30
Bhakti 6d8d1ab5f8 Merge branch 'frontend' of https://git.kska.io/notkshitij/status200 into bhakti 2025-02-23 03:10:30 +05:30
notkshitij 928c3fbb12 Merged Bhakti's changes with Ombase's changes in frontend testing branch 2025-02-23 03:08:19 +05:30
Bhakti c4eb3e940e Changes made to Login and SignUp 2025-02-23 03:06:23 +05:30
Bhakti 43613b60ce landing successful 2025-02-23 03:05:24 +05:30
notkshitij 82f457406a Pulled Ombase's changes till now. 2025-02-23 03:01:52 +05:30
atharvaombase ec2f1a939b Fix:Changed the CropList to CropTable 2025-02-23 02:55:56 +05:30
atharvaombase 490668ff61 Feat:Added table to display crop details 2025-02-23 02:55:04 +05:30
atharvaombase 21a21303f8 Fix:Added Padding the select 2025-02-23 02:54:27 +05:30
atharvaombase 7edeef04f7 Fix:Added padding to select menu 2025-02-23 02:51:39 +05:30
atharvaombase 793a0867dd Fix:Added farmId as a prop and posted 2025-02-23 02:51:03 +05:30
atharvaombase a585ac58f6 Feat:Sent farmId prop to Farm.jsx 2025-02-23 02:27:21 +05:30
atharvaombase d16b59edc0 Feat:Sent props to AddCrop 2025-02-23 02:26:45 +05:30
atharvaombase 9e6ccc0343 Fix:changed fetch body for sending farm id 2025-02-23 02:25:26 +05:30
atharvaombase 3215da670e Fix:Removed overlapping svg 2025-02-23 02:24:37 +05:30
notkshitij 6e813383fb Updated readme file reflecting the purpose of this branch, i.e. main. 2025-02-23 01:44:57 +05:30
notkshitij 0758934b91 Added a bit more descriptive readme for training branch. 2025-02-23 01:42:07 +05:30
notkshitij 5015db6edb Added dependencies in requirements.txt file. 2025-02-22 23:09:44 +05:30
notkshitij 19073e945b Moved test2.py to app-old. This implementation pulls model and stuff from hugging faces. 2025-02-22 23:08:33 +05:30
notkshitij 0ea087b5c1 Removed some unclear sample images and added new better ones. 2025-02-22 23:07:44 +05:30
notkshitij c254f356bf test2, i.e. vishnu is the chosen model. Shall be using that going forward. Perfectly working right now. Will be attempting to locally reference it now. 2025-02-22 22:55:33 +05:30
notkshitij f43890faab Added gitignore file excluding python venv folders. 2025-02-22 22:55:33 +05:30
notkshitij 559b806a59 Added sample crop images. 2025-02-22 22:55:33 +05:30
notkshitij 8830798bd4 Moved test1, test3 and test4 to archive folder. 2025-02-22 22:54:54 +05:30
notkshitij f11f46b3a5 Added test2 converted from python to js. Using vishnun0027's pretrained model. 2025-02-22 19:51:52 +05:30
notkshitij 9ef589d638 Added more class labels in test 3. 2025-02-22 19:34:37 +05:30
notkshitij 33a634ef7b Test 3 using TonyStarkD99 large model. Works like a charm. Need to increase the class labels. 2025-02-22 19:34:17 +05:30
notkshitij ba537242e8 Test 2, using vishnun0027 model. 2025-02-22 19:20:48 +05:30
notkshitij 0b5ef59a62 Working python implementation for wambugu71 model. 2025-02-22 19:05:23 +05:30
notkshitij 33e352a1ef Added one line description in README. 2025-02-22 15:36:19 +05:30
936 changed files with 218229 additions and 22 deletions
+2 -1
View File
@@ -1 +1,2 @@
Backend/package-lock.json package-lock.json
node_modules/
+2
View File
@@ -1,3 +1,5 @@
package-lock.json
# Logs # Logs
logs logs
*.log *.log
+1
View File
@@ -39,6 +39,7 @@ const getUserFarms = async (req, res) => {
// Get a single farm by ID // Get a single farm by ID
const getFarmById = async (req, res) => { const getFarmById = async (req, res) => {
try { try {
console.log("also i am clla ing", "My farm id is : ", req.params.farmId);
const farm = await Farm.findById(req.params.farmId) const farm = await Farm.findById(req.params.farmId)
.populate("crops") .populate("crops")
.populate("finances"); .populate("finances");
+47 -1
View File
@@ -2,15 +2,55 @@ const Finance = require("../Models/finance.model.js");
const Farm = require("../Models/farm.model.js"); const Farm = require("../Models/farm.model.js");
// Create finance record for a farm // Create finance record for a farm
// const createFinance = async (req, res) => {
// try {
// const { farm } = req.body;
// console.log("My farm id is which is going to be created : ", req.body);
// // Check if the farm exists
// const existingFarm = await Farm.findById(farm);
// if (!existingFarm)
// return res.status(404).json({ message: "Farm not found" });
// const finance = new Finance({
// farm,
// transactions: [],
// totalExpenses: 0,
// totalRevenue: 0,
// });
// await finance.save();
// // Link finance to farm
// existingFarm.finances = finance._id;
// await existingFarm.save();
// res.status(201).json(finance);
// } catch (error) {
// res.status(500).json({ message: error.message });
// }
// };
const createFinance = async (req, res) => { const createFinance = async (req, res) => {
try { try {
const { farm } = req.body; const { farm } = req.body;
console.log("My farm id is which is going to be created : ", farm);
// Check if the farm exists // Check if the farm exists
const existingFarm = await Farm.findById(farm); const existingFarm = await Farm.findById(farm);
if (!existingFarm) if (!existingFarm) {
return res.status(404).json({ message: "Farm not found" }); return res.status(404).json({ message: "Farm not found" });
}
// Check if finance already exists for this farm
if (existingFarm.finances) {
return res
.status(400)
.json({ message: "Finance already exists for this farm" });
}
// Create finance entry
const finance = new Finance({ const finance = new Finance({
farm, farm,
transactions: [], transactions: [],
@@ -50,6 +90,12 @@ const addTransaction = async (req, res) => {
try { try {
const { type, amount, description } = req.body; const { type, amount, description } = req.body;
console.log("My type is : ", type);
console.log("My amount is : ", amount);
console.log("My description is : ", description);
console.log("My finance id is : ", req.params.financeId);
const finance = await Finance.findById(req.params.financeId); const finance = await Finance.findById(req.params.financeId);
if (!finance) if (!finance)
return res.status(404).json({ message: "Finance record not found" }); return res.status(404).json({ message: "Finance record not found" });
+22 -7
View File
@@ -4,11 +4,28 @@ const { uploadOnCloudinary } = require("../Utils/cloudinary.js");
const sendEmail = require("../Utils/sendmail.js"); const sendEmail = require("../Utils/sendmail.js");
const crypto = require("crypto"); const crypto = require("crypto");
const jwt = require("jsonwebtoken"); const jwt = require("jsonwebtoken");
const sha1 = require("sha1");
const axios = require("axios");
// Register or Sign up new User -- Done // Register or Sign up new User -- Done
const registerUser = catchAsyncErrors(async (req, res) => { const registerUser = catchAsyncErrors(async (req, res) => {
const { name, email, password, role } = req.body; const { name, email, password, role } = req.body;
// Strong password policy
const strongPasswordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$/;
if (!strongPasswordRegex.test(password)) {
return res.status(400).json({ success: false, message: "Password must be at least 8 characters long and include uppercase, lowercase, number, and special character." });
}
// Check for data breach with haveibeenpwned.com
const hashed = sha1(password).toUpperCase();
const prefix = hashed.slice(0, 5);
const suffix = hashed.slice(5);
const response = await axios.get(`https://api.pwnedpasswords.com/range/${prefix}`);
if (response.data.includes(suffix)) {
return res.status(400).json({ success: false, message: "This password has appeared in a data breach. Please choose a different one." });
}
const user = await User.create({ const user = await User.create({
name, name,
email, email,
@@ -65,12 +82,12 @@ const loginUser = catchAsyncErrors(async (req, res) => {
return res return res
.status(200) .status(200)
.cookie(process.env.TOKEN_NAME, token, { .cookie("uid", token, {
httpOnly: true, // Prevent access from JavaScript (recommended for security)
secure: false, // ⚠️ Set to `false` for localhost
sameSite: "Lax", // Use "Lax" instead of "None" for better compatibility
path: "/", path: "/",
sameSite: "None", expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
secure: process.env.NODE_ENV === "production",
httpOnly: true,
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
}) })
.json({ .json({
success: true, success: true,
@@ -260,8 +277,6 @@ const resetPassword = catchAsyncErrors(async (req, res) => {
// get user personal details // get user personal details
const getUserDetails = catchAsyncErrors(async (req, res) => { const getUserDetails = catchAsyncErrors(async (req, res) => {
const user = await User.findById(req.user._id); const user = await User.findById(req.user._id);
if (!user) { if (!user) {
+9 -5
View File
@@ -3,19 +3,23 @@ const catchAsyncErrors = require("../Middlewares/catchAsyncErrors.js");
const DB_connect = catchAsyncErrors(async () => { const DB_connect = catchAsyncErrors(async () => {
try { try {
const connectionInstance = await mongoose.connect( const dbUri = `${process.env.MONGODB_URI}/${process.env.DATABASE_NAME}?authSource=admin`;
`${process.env.MONGODB_URI}/${process.env.DATABASE_NAME}` const connectionInstance = await mongoose.connect(dbUri, {
); useNewUrlParser: true,
useUnifiedTopology: true,
});
if (!connectionInstance) { if (!connectionInstance) {
console.log("MongoDB connection failed"); console.log("MongoDB connection failed");
} } else {
console.log( console.log(
"MongoDB connected Successfully on server : " + "MongoDB connected Successfully to:",
connectionInstance.connection.host connectionInstance.connection.host
); );
}
} catch (error) { } catch (error) {
console.log("MongoDB connection failed due to some error :", error); console.log("MongoDB connection failed due to some error :", error);
} }
}); });
module.exports = DB_connect; module.exports = DB_connect;
+11
View File
@@ -0,0 +1,11 @@
const rateLimit = require("express-rate-limit");
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 login requests per windowMs
message: "Too many login attempts. Try again in 15 minutes.",
standardHeaders: true,
legacyHeaders: false,
});
module.exports = { loginLimiter };
+3 -1
View File
@@ -19,11 +19,13 @@ const { checkAuthenticated } = require("../Middlewares/authentication.js");
const upload = require("../Middlewares/multer.js"); const upload = require("../Middlewares/multer.js");
const { loginLimiter } = require("../Middlewares/rateLimiter");
const router = express.Router(); const router = express.Router();
router.route("/register").post(registerUser); router.route("/register").post(registerUser);
router.route("/login").post(loginUser); router.route("/login").post(loginLimiter, loginUser);
router.route("/password/forgot").post(forgetPassword); router.route("/password/forgot").post(forgetPassword);
+11 -2
View File
@@ -1,6 +1,7 @@
const express = require("express"); const express = require("express");
const cors = require("cors"); const cors = require("cors");
const cookieParser = require("cookie-parser"); const cookieParser = require("cookie-parser");
const helmet = require("helmet");
const userRoute = require("./Routes/user.routes.js"); const userRoute = require("./Routes/user.routes.js");
const farmRoute = require("./Routes/farm.routes.js"); const farmRoute = require("./Routes/farm.routes.js");
@@ -17,6 +18,8 @@ dotenv.config({
const app = express(); const app = express();
app.use(helmet()); // Secure headers
const corsOptions = { const corsOptions = {
origin: process.env.FRONTEND_URI, origin: process.env.FRONTEND_URI,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE", methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
@@ -30,7 +33,7 @@ app.use(express.static("public"));
app.use(cookieParser()); app.use(cookieParser());
app.get("/", (req, res) => { app.get("/", (req, res) => {
return res.send("Hiddskpkpk..."); return res.send("Server is running...");
}); });
app.use("/api/v1", userRoute); app.use("/api/v1", userRoute);
@@ -43,6 +46,12 @@ app.use("/api/v1/finance", financeRoute);
app.use("/api/v1/task", taskRoute); app.use("/api/v1/task", taskRoute);
// Redirect HTTP to HTTPS (works behind proxy)
app.use((req, res, next) => {
if (req.headers["x-forwarded-proto"] !== "https" && process.env.NODE_ENV === "production") {
return res.redirect(`https://${req.headers.host}${req.url}`);
}
next();
});
module.exports = app; module.exports = app;
+4
View File
@@ -11,16 +11,20 @@
"description": "", "description": "",
"dependencies": { "dependencies": {
"@google/generative-ai": "^0.24.1", "@google/generative-ai": "^0.24.1",
"axios": "^1.6.8",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"cloudinary": "^2.7.0", "cloudinary": "^2.7.0",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"express": "^5.1.0", "express": "^5.1.0",
"express-rate-limit": "^6.7.0",
"helmet": "^7.0.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"mongoose": "^8.16.0", "mongoose": "^8.16.0",
"multer": "^2.0.1", "multer": "^2.0.1",
"nodemailer": "^7.0.3", "nodemailer": "^7.0.3",
"sha1": "^1.1.1",
"socket.io": "^4.8.1" "socket.io": "^4.8.1"
}, },
"devDependencies": { "devDependencies": {
+1
View File
@@ -0,0 +1 @@
VITE_API_URL=http://localhost:8000
+25
View File
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
package-lock.json
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+142
View File
@@ -0,0 +1,142 @@
{
"hash": "2bafedf9",
"configHash": "7e00041b",
"lockfileHash": "a954eb91",
"browserHash": "c3bc7b53",
"optimized": {
"react": {
"src": "../../node_modules/react/index.js",
"file": "react.js",
"fileHash": "902ee93a",
"needsInterop": true
},
"react-dom/client": {
"src": "../../node_modules/react-dom/client.js",
"file": "react-dom_client.js",
"fileHash": "cfbeda6d",
"needsInterop": true
},
"react-router-dom": {
"src": "../../node_modules/react-router-dom/dist/index.js",
"file": "react-router-dom.js",
"fileHash": "216229fd",
"needsInterop": false
},
"react-redux": {
"src": "../../node_modules/react-redux/dist/react-redux.mjs",
"file": "react-redux.js",
"fileHash": "b9f679da",
"needsInterop": false
},
"@reduxjs/toolkit": {
"src": "../../node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs",
"file": "@reduxjs_toolkit.js",
"fileHash": "13da79f3",
"needsInterop": false
},
"socket.io-client": {
"src": "../../node_modules/socket.io-client/build/esm/index.js",
"file": "socket__io-client.js",
"fileHash": "ab2fcae8",
"needsInterop": false
},
"react-icons/io": {
"src": "../../node_modules/react-icons/io/index.mjs",
"file": "react-icons_io.js",
"fileHash": "fb80952c",
"needsInterop": false
},
"react-icons/fa6": {
"src": "../../node_modules/react-icons/fa6/index.mjs",
"file": "react-icons_fa6.js",
"fileHash": "da456fb8",
"needsInterop": false
},
"react-icons/ri": {
"src": "../../node_modules/react-icons/ri/index.mjs",
"file": "react-icons_ri.js",
"fileHash": "6e092d47",
"needsInterop": false
},
"react-icons/bs": {
"src": "../../node_modules/react-icons/bs/index.mjs",
"file": "react-icons_bs.js",
"fileHash": "c070a6ed",
"needsInterop": false
},
"react-icons/fa": {
"src": "../../node_modules/react-icons/fa/index.mjs",
"file": "react-icons_fa.js",
"fileHash": "aa81607f",
"needsInterop": false
},
"react-icons/md": {
"src": "../../node_modules/react-icons/md/index.mjs",
"file": "react-icons_md.js",
"fileHash": "60d442c6",
"needsInterop": false
},
"react-icons/io5": {
"src": "../../node_modules/react-icons/io5/index.mjs",
"file": "react-icons_io5.js",
"fileHash": "5d65fe60",
"needsInterop": false
},
"framer-motion": {
"src": "../../node_modules/framer-motion/dist/es/index.mjs",
"file": "framer-motion.js",
"fileHash": "05223771",
"needsInterop": false
},
"react-intersection-observer": {
"src": "../../node_modules/react-intersection-observer/dist/index.mjs",
"file": "react-intersection-observer.js",
"fileHash": "575187c6",
"needsInterop": false
},
"react-chartjs-2": {
"src": "../../node_modules/react-chartjs-2/dist/index.js",
"file": "react-chartjs-2.js",
"fileHash": "07d12b80",
"needsInterop": false
},
"chart.js": {
"src": "../../node_modules/chart.js/dist/chart.js",
"file": "chart__js.js",
"fileHash": "39dbe037",
"needsInterop": false
},
"react-apexcharts": {
"src": "../../node_modules/react-apexcharts/dist/react-apexcharts.min.js",
"file": "react-apexcharts.js",
"fileHash": "2bdb7b94",
"needsInterop": true
},
"react-typewriter-effect": {
"src": "../../node_modules/react-typewriter-effect/dist/index.js",
"file": "react-typewriter-effect.js",
"fileHash": "574603a4",
"needsInterop": true
}
},
"chunks": {
"chunk-UU7TO5PY": {
"file": "chunk-UU7TO5PY.js"
},
"chunk-2YIK36WJ": {
"file": "chunk-2YIK36WJ.js"
},
"chunk-UHINIFCJ": {
"file": "chunk-UHINIFCJ.js"
},
"chunk-SD42HLFO": {
"file": "chunk-SD42HLFO.js"
},
"chunk-W4EHDCLL": {
"file": "chunk-W4EHDCLL.js"
},
"chunk-EWTE5DHJ": {
"file": "chunk-EWTE5DHJ.js"
}
}
}
+100
View File
@@ -0,0 +1,100 @@
import {
Animation,
Animations,
ArcElement,
BarController,
BarElement,
BasePlatform,
BasicPlatform,
BubbleController,
CategoryScale,
Chart,
DatasetController,
DomPlatform,
DoughnutController,
Element,
Interaction,
LineController,
LineElement,
LinearScale,
LogarithmicScale,
PieController,
PointElement,
PolarAreaController,
RadarController,
RadialLinearScale,
Scale,
ScatterController,
Ticks,
TimeScale,
TimeSeriesScale,
_detectPlatform,
adapters,
animator,
controllers,
defaults,
elements,
index,
layouts,
plugin_colors,
plugin_decimation,
plugin_legend,
plugin_subtitle,
plugin_title,
plugin_tooltip,
plugins,
registerables,
registry,
scales
} from "./chunk-2YIK36WJ.js";
import "./chunk-EWTE5DHJ.js";
export {
Animation,
Animations,
ArcElement,
BarController,
BarElement,
BasePlatform,
BasicPlatform,
BubbleController,
CategoryScale,
Chart,
plugin_colors as Colors,
DatasetController,
plugin_decimation as Decimation,
DomPlatform,
DoughnutController,
Element,
index as Filler,
Interaction,
plugin_legend as Legend,
LineController,
LineElement,
LinearScale,
LogarithmicScale,
PieController,
PointElement,
PolarAreaController,
RadarController,
RadialLinearScale,
Scale,
ScatterController,
plugin_subtitle as SubTitle,
Ticks,
TimeScale,
TimeSeriesScale,
plugin_title as Title,
plugin_tooltip as Tooltip,
adapters as _adapters,
_detectPlatform,
animator,
controllers,
defaults,
elements,
layouts,
plugins,
registerables,
registry,
scales
};
//# sourceMappingURL=chart__js.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+45
View File
@@ -0,0 +1,45 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
export {
__esm,
__commonJS,
__export,
__toESM,
__toCommonJS,
__publicField
};
//# sourceMappingURL=chunk-EWTE5DHJ.js.map
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+149
View File
@@ -0,0 +1,149 @@
import {
require_react
} from "./chunk-W4EHDCLL.js";
import {
__toESM
} from "./chunk-EWTE5DHJ.js";
// node_modules/react-icons/lib/iconBase.mjs
var import_react2 = __toESM(require_react(), 1);
// node_modules/react-icons/lib/iconContext.mjs
var import_react = __toESM(require_react(), 1);
var DefaultContext = {
color: void 0,
size: void 0,
className: void 0,
style: void 0,
attr: void 0
};
var IconContext = import_react.default.createContext && import_react.default.createContext(DefaultContext);
// node_modules/react-icons/lib/iconBase.mjs
var _excluded = ["attr", "size", "title"];
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
}
return target;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function(r2) {
return Object.getOwnPropertyDescriptor(e, r2).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), true).forEach(function(r2) {
_defineProperty(e, r2, t[r2]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r2) {
Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2));
});
}
return e;
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function Tree2Element(tree) {
return tree && tree.map((node, i) => import_react2.default.createElement(node.tag, _objectSpread({
key: i
}, node.attr), Tree2Element(node.child)));
}
function GenIcon(data) {
return (props) => import_react2.default.createElement(IconBase, _extends({
attr: _objectSpread({}, data.attr)
}, props), Tree2Element(data.child));
}
function IconBase(props) {
var elem = (conf) => {
var {
attr,
size,
title
} = props, svgProps = _objectWithoutProperties(props, _excluded);
var computedSize = size || conf.size || "1em";
var className;
if (conf.className) className = conf.className;
if (props.className) className = (className ? className + " " : "") + props.className;
return import_react2.default.createElement("svg", _extends({
stroke: "currentColor",
fill: "currentColor",
strokeWidth: "0"
}, conf.attr, attr, svgProps, {
className,
style: _objectSpread(_objectSpread({
color: props.color || conf.color
}, conf.style), props.style),
height: computedSize,
width: computedSize,
xmlns: "http://www.w3.org/2000/svg"
}), title && import_react2.default.createElement("title", null, title), props.children);
};
return IconContext !== void 0 ? import_react2.default.createElement(IconContext.Consumer, null, (conf) => elem(conf)) : elem(DefaultContext);
}
export {
GenIcon
};
//# sourceMappingURL=chunk-SD42HLFO.js.map
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../node_modules/react-icons/lib/iconBase.mjs", "../../node_modules/react-icons/lib/iconContext.mjs"],
"sourcesContent": ["var _excluded = [\"attr\", \"size\", \"title\"];\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } } return target; }\nfunction _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : i + \"\"; }\nfunction _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\nimport React from \"react\";\nimport { IconContext, DefaultContext } from \"./iconContext.mjs\";\nfunction Tree2Element(tree) {\n return tree && tree.map((node, i) => /*#__PURE__*/React.createElement(node.tag, _objectSpread({\n key: i\n }, node.attr), Tree2Element(node.child)));\n}\nexport function GenIcon(data) {\n return props => /*#__PURE__*/React.createElement(IconBase, _extends({\n attr: _objectSpread({}, data.attr)\n }, props), Tree2Element(data.child));\n}\nexport function IconBase(props) {\n var elem = conf => {\n var {\n attr,\n size,\n title\n } = props,\n svgProps = _objectWithoutProperties(props, _excluded);\n var computedSize = size || conf.size || \"1em\";\n var className;\n if (conf.className) className = conf.className;\n if (props.className) className = (className ? className + \" \" : \"\") + props.className;\n return /*#__PURE__*/React.createElement(\"svg\", _extends({\n stroke: \"currentColor\",\n fill: \"currentColor\",\n strokeWidth: \"0\"\n }, conf.attr, attr, svgProps, {\n className: className,\n style: _objectSpread(_objectSpread({\n color: props.color || conf.color\n }, conf.style), props.style),\n height: computedSize,\n width: computedSize,\n xmlns: \"http://www.w3.org/2000/svg\"\n }), title && /*#__PURE__*/React.createElement(\"title\", null, title), props.children);\n };\n return IconContext !== undefined ? /*#__PURE__*/React.createElement(IconContext.Consumer, null, conf => elem(conf)) : elem(DefaultContext);\n}", "import React from \"react\";\nexport var DefaultContext = {\n color: undefined,\n size: undefined,\n className: undefined,\n style: undefined,\n attr: undefined\n};\nexport var IconContext = React.createContext && /*#__PURE__*/React.createContext(DefaultContext);"],
"mappings": ";;;;;;;;AASA,IAAAA,gBAAkB;;;ACTlB,mBAAkB;AACX,IAAI,iBAAiB;AAAA,EAC1B,OAAO;AAAA,EACP,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,EACP,MAAM;AACR;AACO,IAAI,cAAc,aAAAC,QAAM,iBAA8B,aAAAA,QAAM,cAAc,cAAc;;;ADR/F,IAAI,YAAY,CAAC,QAAQ,QAAQ,OAAO;AACxC,SAAS,yBAAyB,QAAQ,UAAU;AAAE,MAAI,UAAU,KAAM,QAAO,CAAC;AAAG,MAAI,SAAS,8BAA8B,QAAQ,QAAQ;AAAG,MAAI,KAAK;AAAG,MAAI,OAAO,uBAAuB;AAAE,QAAI,mBAAmB,OAAO,sBAAsB,MAAM;AAAG,SAAK,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAAE,YAAM,iBAAiB,CAAC;AAAG,UAAI,SAAS,QAAQ,GAAG,KAAK,EAAG;AAAU,UAAI,CAAC,OAAO,UAAU,qBAAqB,KAAK,QAAQ,GAAG,EAAG;AAAU,aAAO,GAAG,IAAI,OAAO,GAAG;AAAA,IAAG;AAAA,EAAE;AAAE,SAAO;AAAQ;AAC3e,SAAS,8BAA8B,QAAQ,UAAU;AAAE,MAAI,UAAU,KAAM,QAAO,CAAC;AAAG,MAAI,SAAS,CAAC;AAAG,WAAS,OAAO,QAAQ;AAAE,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AAAE,UAAI,SAAS,QAAQ,GAAG,KAAK,EAAG;AAAU,aAAO,GAAG,IAAI,OAAO,GAAG;AAAA,IAAG;AAAA,EAAE;AAAE,SAAO;AAAQ;AACtR,SAAS,WAAW;AAAE,aAAW,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI,SAAU,QAAQ;AAAE,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AAAE,UAAI,SAAS,UAAU,CAAC;AAAG,eAAS,OAAO,QAAQ;AAAE,YAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AAAE,iBAAO,GAAG,IAAI,OAAO,GAAG;AAAA,QAAG;AAAA,MAAE;AAAA,IAAE;AAAE,WAAO;AAAA,EAAQ;AAAG,SAAO,SAAS,MAAM,MAAM,SAAS;AAAG;AAClV,SAAS,QAAQ,GAAG,GAAG;AAAE,MAAI,IAAI,OAAO,KAAK,CAAC;AAAG,MAAI,OAAO,uBAAuB;AAAE,QAAI,IAAI,OAAO,sBAAsB,CAAC;AAAG,UAAM,IAAI,EAAE,OAAO,SAAUC,IAAG;AAAE,aAAO,OAAO,yBAAyB,GAAGA,EAAC,EAAE;AAAA,IAAY,CAAC,IAAI,EAAE,KAAK,MAAM,GAAG,CAAC;AAAA,EAAG;AAAE,SAAO;AAAG;AAC9P,SAAS,cAAc,GAAG;AAAE,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AAAE,QAAI,IAAI,QAAQ,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC;AAAG,QAAI,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAE,EAAE,QAAQ,SAAUA,IAAG;AAAE,sBAAgB,GAAGA,IAAG,EAAEA,EAAC,CAAC;AAAA,IAAG,CAAC,IAAI,OAAO,4BAA4B,OAAO,iBAAiB,GAAG,OAAO,0BAA0B,CAAC,CAAC,IAAI,QAAQ,OAAO,CAAC,CAAC,EAAE,QAAQ,SAAUA,IAAG;AAAE,aAAO,eAAe,GAAGA,IAAG,OAAO,yBAAyB,GAAGA,EAAC,CAAC;AAAA,IAAG,CAAC;AAAA,EAAG;AAAE,SAAO;AAAG;AACtb,SAAS,gBAAgB,KAAK,KAAK,OAAO;AAAE,QAAM,eAAe,GAAG;AAAG,MAAI,OAAO,KAAK;AAAE,WAAO,eAAe,KAAK,KAAK,EAAE,OAAc,YAAY,MAAM,cAAc,MAAM,UAAU,KAAK,CAAC;AAAA,EAAG,OAAO;AAAE,QAAI,GAAG,IAAI;AAAA,EAAO;AAAE,SAAO;AAAK;AAC3O,SAAS,eAAe,GAAG;AAAE,MAAI,IAAI,aAAa,GAAG,QAAQ;AAAG,SAAO,YAAY,OAAO,IAAI,IAAI,IAAI;AAAI;AAC1G,SAAS,aAAa,GAAG,GAAG;AAAE,MAAI,YAAY,OAAO,KAAK,CAAC,EAAG,QAAO;AAAG,MAAI,IAAI,EAAE,OAAO,WAAW;AAAG,MAAI,WAAW,GAAG;AAAE,QAAI,IAAI,EAAE,KAAK,GAAG,KAAK,SAAS;AAAG,QAAI,YAAY,OAAO,EAAG,QAAO;AAAG,UAAM,IAAI,UAAU,8CAA8C;AAAA,EAAG;AAAE,UAAQ,aAAa,IAAI,SAAS,QAAQ,CAAC;AAAG;AAGvT,SAAS,aAAa,MAAM;AAC1B,SAAO,QAAQ,KAAK,IAAI,CAAC,MAAM,MAAmB,cAAAC,QAAM,cAAc,KAAK,KAAK,cAAc;AAAA,IAC5F,KAAK;AAAA,EACP,GAAG,KAAK,IAAI,GAAG,aAAa,KAAK,KAAK,CAAC,CAAC;AAC1C;AACO,SAAS,QAAQ,MAAM;AAC5B,SAAO,WAAsB,cAAAA,QAAM,cAAc,UAAU,SAAS;AAAA,IAClE,MAAM,cAAc,CAAC,GAAG,KAAK,IAAI;AAAA,EACnC,GAAG,KAAK,GAAG,aAAa,KAAK,KAAK,CAAC;AACrC;AACO,SAAS,SAAS,OAAO;AAC9B,MAAI,OAAO,UAAQ;AACjB,QAAI;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,OACJ,WAAW,yBAAyB,OAAO,SAAS;AACtD,QAAI,eAAe,QAAQ,KAAK,QAAQ;AACxC,QAAI;AACJ,QAAI,KAAK,UAAW,aAAY,KAAK;AACrC,QAAI,MAAM,UAAW,cAAa,YAAY,YAAY,MAAM,MAAM,MAAM;AAC5E,WAAoB,cAAAA,QAAM,cAAc,OAAO,SAAS;AAAA,MACtD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,IACf,GAAG,KAAK,MAAM,MAAM,UAAU;AAAA,MAC5B;AAAA,MACA,OAAO,cAAc,cAAc;AAAA,QACjC,OAAO,MAAM,SAAS,KAAK;AAAA,MAC7B,GAAG,KAAK,KAAK,GAAG,MAAM,KAAK;AAAA,MAC3B,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC,GAAG,SAAsB,cAAAA,QAAM,cAAc,SAAS,MAAM,KAAK,GAAG,MAAM,QAAQ;AAAA,EACrF;AACA,SAAO,gBAAgB,SAAyB,cAAAA,QAAM,cAAc,YAAY,UAAU,MAAM,UAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,cAAc;AAC3I;",
"names": ["import_react", "React", "r", "React"]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+172
View File
@@ -0,0 +1,172 @@
import {
__commonJS
} from "./chunk-EWTE5DHJ.js";
// node_modules/object-assign/index.js
var require_object_assign = __commonJS({
"node_modules/object-assign/index.js"(exports, module) {
"use strict";
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === void 0) {
throw new TypeError("Object.assign cannot be called with null or undefined");
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
var test1 = new String("abc");
test1[5] = "de";
if (Object.getOwnPropertyNames(test1)[0] === "5") {
return false;
}
var test2 = {};
for (var i = 0; i < 10; i++) {
test2["_" + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function(n) {
return test2[n];
});
if (order2.join("") !== "0123456789") {
return false;
}
var test3 = {};
"abcdefghijklmnopqrst".split("").forEach(function(letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join("") !== "abcdefghijklmnopqrst") {
return false;
}
return true;
} catch (err) {
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function(target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
}
});
// node_modules/prop-types/lib/ReactPropTypesSecret.js
var require_ReactPropTypesSecret = __commonJS({
"node_modules/prop-types/lib/ReactPropTypesSecret.js"(exports, module) {
"use strict";
var ReactPropTypesSecret = "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";
module.exports = ReactPropTypesSecret;
}
});
// node_modules/prop-types/lib/has.js
var require_has = __commonJS({
"node_modules/prop-types/lib/has.js"(exports, module) {
module.exports = Function.call.bind(Object.prototype.hasOwnProperty);
}
});
// node_modules/prop-types/checkPropTypes.js
var require_checkPropTypes = __commonJS({
"node_modules/prop-types/checkPropTypes.js"(exports, module) {
"use strict";
var printWarning = function() {
};
if (true) {
ReactPropTypesSecret = require_ReactPropTypesSecret();
loggedTypeFailures = {};
has = require_has();
printWarning = function(text) {
var message = "Warning: " + text;
if (typeof console !== "undefined") {
console.error(message);
}
try {
throw new Error(message);
} catch (x) {
}
};
}
var ReactPropTypesSecret;
var loggedTypeFailures;
var has;
function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
if (true) {
for (var typeSpecName in typeSpecs) {
if (has(typeSpecs, typeSpecName)) {
var error;
try {
if (typeof typeSpecs[typeSpecName] !== "function") {
var err = Error(
(componentName || "React class") + ": " + location + " type `" + typeSpecName + "` is invalid; it must be a function, usually from the `prop-types` package, but received `" + typeof typeSpecs[typeSpecName] + "`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`."
);
err.name = "Invariant Violation";
throw err;
}
error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
} catch (ex) {
error = ex;
}
if (error && !(error instanceof Error)) {
printWarning(
(componentName || "React class") + ": type specification of " + location + " `" + typeSpecName + "` is invalid; the type checker function must return `null` or an `Error` but returned a " + typeof error + ". You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument)."
);
}
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
loggedTypeFailures[error.message] = true;
var stack = getStack ? getStack() : "";
printWarning(
"Failed " + location + " type: " + error.message + (stack != null ? stack : "")
);
}
}
}
}
}
checkPropTypes.resetWarningCache = function() {
if (true) {
loggedTypeFailures = {};
}
};
module.exports = checkPropTypes;
}
});
export {
require_object_assign,
require_ReactPropTypesSecret,
require_has,
require_checkPropTypes
};
/*! Bundled license information:
object-assign/index.js:
(*
object-assign
(c) Sindre Sorhus
@license MIT
*)
*/
//# sourceMappingURL=chunk-UU7TO5PY.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+190
View File
@@ -0,0 +1,190 @@
import {
BarController,
BubbleController,
Chart,
DoughnutController,
LineController,
PieController,
PolarAreaController,
RadarController,
ScatterController
} from "./chunk-2YIK36WJ.js";
import {
require_react
} from "./chunk-W4EHDCLL.js";
import {
__toESM
} from "./chunk-EWTE5DHJ.js";
// node_modules/react-chartjs-2/dist/index.js
var import_react = __toESM(require_react());
var defaultDatasetIdKey = "label";
function reforwardRef(ref, value) {
if (typeof ref === "function") {
ref(value);
} else if (ref) {
ref.current = value;
}
}
function setOptions(chart, nextOptions) {
const options = chart.options;
if (options && nextOptions) {
Object.assign(options, nextOptions);
}
}
function setLabels(currentData, nextLabels) {
currentData.labels = nextLabels;
}
function setDatasets(currentData, nextDatasets) {
let datasetIdKey = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : defaultDatasetIdKey;
const addedDatasets = [];
currentData.datasets = nextDatasets.map((nextDataset) => {
const currentDataset = currentData.datasets.find((dataset) => dataset[datasetIdKey] === nextDataset[datasetIdKey]);
if (!currentDataset || !nextDataset.data || addedDatasets.includes(currentDataset)) {
return {
...nextDataset
};
}
addedDatasets.push(currentDataset);
Object.assign(currentDataset, nextDataset);
return currentDataset;
});
}
function cloneData(data) {
let datasetIdKey = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : defaultDatasetIdKey;
const nextData = {
labels: [],
datasets: []
};
setLabels(nextData, data.labels);
setDatasets(nextData, data.datasets, datasetIdKey);
return nextData;
}
function getDatasetAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "dataset", {
intersect: true
}, false);
}
function getElementAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "nearest", {
intersect: true
}, false);
}
function getElementsAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "index", {
intersect: true
}, false);
}
function ChartComponent(props, ref) {
const { height = 150, width = 300, redraw = false, datasetIdKey, type, data, options, plugins = [], fallbackContent, updateMode, ...canvasProps } = props;
const canvasRef = (0, import_react.useRef)(null);
const chartRef = (0, import_react.useRef)(null);
const renderChart = () => {
if (!canvasRef.current) return;
chartRef.current = new Chart(canvasRef.current, {
type,
data: cloneData(data, datasetIdKey),
options: options && {
...options
},
plugins
});
reforwardRef(ref, chartRef.current);
};
const destroyChart = () => {
reforwardRef(ref, null);
if (chartRef.current) {
chartRef.current.destroy();
chartRef.current = null;
}
};
(0, import_react.useEffect)(() => {
if (!redraw && chartRef.current && options) {
setOptions(chartRef.current, options);
}
}, [
redraw,
options
]);
(0, import_react.useEffect)(() => {
if (!redraw && chartRef.current) {
setLabels(chartRef.current.config.data, data.labels);
}
}, [
redraw,
data.labels
]);
(0, import_react.useEffect)(() => {
if (!redraw && chartRef.current && data.datasets) {
setDatasets(chartRef.current.config.data, data.datasets, datasetIdKey);
}
}, [
redraw,
data.datasets
]);
(0, import_react.useEffect)(() => {
if (!chartRef.current) return;
if (redraw) {
destroyChart();
setTimeout(renderChart);
} else {
chartRef.current.update(updateMode);
}
}, [
redraw,
options,
data.labels,
data.datasets,
updateMode
]);
(0, import_react.useEffect)(() => {
if (!chartRef.current) return;
destroyChart();
setTimeout(renderChart);
}, [
type
]);
(0, import_react.useEffect)(() => {
renderChart();
return () => destroyChart();
}, []);
return import_react.default.createElement("canvas", {
ref: canvasRef,
role: "img",
height,
width,
...canvasProps
}, fallbackContent);
}
var Chart2 = (0, import_react.forwardRef)(ChartComponent);
function createTypedChart(type, registerables) {
Chart.register(registerables);
return (0, import_react.forwardRef)((props, ref) => import_react.default.createElement(Chart2, {
...props,
ref,
type
}));
}
var Line = createTypedChart("line", LineController);
var Bar = createTypedChart("bar", BarController);
var Radar = createTypedChart("radar", RadarController);
var Doughnut = createTypedChart("doughnut", DoughnutController);
var PolarArea = createTypedChart("polarArea", PolarAreaController);
var Bubble = createTypedChart("bubble", BubbleController);
var Pie = createTypedChart("pie", PieController);
var Scatter = createTypedChart("scatter", ScatterController);
export {
Bar,
Bubble,
Chart2 as Chart,
Doughnut,
Line,
Pie,
PolarArea,
Radar,
Scatter,
getDatasetAtEvent,
getElementAtEvent,
getElementsAtEvent
};
//# sourceMappingURL=react-chartjs-2.js.map
File diff suppressed because one or more lines are too long
+39
View File
@@ -0,0 +1,39 @@
import {
require_react_dom
} from "./chunk-UHINIFCJ.js";
import "./chunk-W4EHDCLL.js";
import {
__commonJS
} from "./chunk-EWTE5DHJ.js";
// node_modules/react-dom/client.js
var require_client = __commonJS({
"node_modules/react-dom/client.js"(exports) {
var m = require_react_dom();
if (false) {
exports.createRoot = m.createRoot;
exports.hydrateRoot = m.hydrateRoot;
} else {
i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
exports.createRoot = function(c, o) {
i.usingClientEntryPoint = true;
try {
return m.createRoot(c, o);
} finally {
i.usingClientEntryPoint = false;
}
};
exports.hydrateRoot = function(c, h, o) {
i.usingClientEntryPoint = true;
try {
return m.hydrateRoot(c, h, o);
} finally {
i.usingClientEntryPoint = false;
}
};
}
var i;
}
});
export default require_client();
//# sourceMappingURL=react-dom_client.js.map
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../node_modules/react-dom/client.js"],
"sourcesContent": ["'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n"],
"mappings": ";;;;;;;;;AAAA;AAAA;AAEA,QAAI,IAAI;AACR,QAAI,OAAuC;AACzC,cAAQ,aAAa,EAAE;AACvB,cAAQ,cAAc,EAAE;AAAA,IAC1B,OAAO;AACD,UAAI,EAAE;AACV,cAAQ,aAAa,SAAS,GAAG,GAAG;AAClC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,WAAW,GAAG,CAAC;AAAA,QAC1B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AACA,cAAQ,cAAc,SAAS,GAAG,GAAG,GAAG;AACtC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,YAAY,GAAG,GAAG,CAAC;AAAA,QAC9B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAjBM;AAAA;AAAA;",
"names": []
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+293
View File
@@ -0,0 +1,293 @@
"use client";
import {
require_react
} from "./chunk-W4EHDCLL.js";
import {
__toESM
} from "./chunk-EWTE5DHJ.js";
// node_modules/react-intersection-observer/dist/index.mjs
var React = __toESM(require_react(), 1);
var React2 = __toESM(require_react(), 1);
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var observerMap = /* @__PURE__ */ new Map();
var RootIds = /* @__PURE__ */ new WeakMap();
var rootId = 0;
var unsupportedValue = void 0;
function defaultFallbackInView(inView) {
unsupportedValue = inView;
}
function getRootId(root) {
if (!root) return "0";
if (RootIds.has(root)) return RootIds.get(root);
rootId += 1;
RootIds.set(root, rootId.toString());
return RootIds.get(root);
}
function optionsToId(options) {
return Object.keys(options).sort().filter(
(key) => options[key] !== void 0
).map((key) => {
return `${key}_${key === "root" ? getRootId(options.root) : options[key]}`;
}).toString();
}
function createObserver(options) {
const id = optionsToId(options);
let instance = observerMap.get(id);
if (!instance) {
const elements = /* @__PURE__ */ new Map();
let thresholds;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
var _a;
const inView = entry.isIntersecting && thresholds.some((threshold) => entry.intersectionRatio >= threshold);
if (options.trackVisibility && typeof entry.isVisible === "undefined") {
entry.isVisible = inView;
}
(_a = elements.get(entry.target)) == null ? void 0 : _a.forEach((callback) => {
callback(inView, entry);
});
});
}, options);
thresholds = observer.thresholds || (Array.isArray(options.threshold) ? options.threshold : [options.threshold || 0]);
instance = {
id,
observer,
elements
};
observerMap.set(id, instance);
}
return instance;
}
function observe(element, callback, options = {}, fallbackInView = unsupportedValue) {
if (typeof window.IntersectionObserver === "undefined" && fallbackInView !== void 0) {
const bounds = element.getBoundingClientRect();
callback(fallbackInView, {
isIntersecting: fallbackInView,
target: element,
intersectionRatio: typeof options.threshold === "number" ? options.threshold : 0,
time: 0,
boundingClientRect: bounds,
intersectionRect: bounds,
rootBounds: bounds
});
return () => {
};
}
const { id, observer, elements } = createObserver(options);
const callbacks = elements.get(element) || [];
if (!elements.has(element)) {
elements.set(element, callbacks);
}
callbacks.push(callback);
observer.observe(element);
return function unobserve() {
callbacks.splice(callbacks.indexOf(callback), 1);
if (callbacks.length === 0) {
elements.delete(element);
observer.unobserve(element);
}
if (elements.size === 0) {
observer.disconnect();
observerMap.delete(id);
}
};
}
function isPlainChildren(props) {
return typeof props.children !== "function";
}
var InView = class extends React.Component {
constructor(props) {
super(props);
__publicField(this, "node", null);
__publicField(this, "_unobserveCb", null);
__publicField(this, "handleNode", (node) => {
if (this.node) {
this.unobserve();
if (!node && !this.props.triggerOnce && !this.props.skip) {
this.setState({ inView: !!this.props.initialInView, entry: void 0 });
}
}
this.node = node ? node : null;
this.observeNode();
});
__publicField(this, "handleChange", (inView, entry) => {
if (inView && this.props.triggerOnce) {
this.unobserve();
}
if (!isPlainChildren(this.props)) {
this.setState({ inView, entry });
}
if (this.props.onChange) {
this.props.onChange(inView, entry);
}
});
this.state = {
inView: !!props.initialInView,
entry: void 0
};
}
componentDidMount() {
this.unobserve();
this.observeNode();
}
componentDidUpdate(prevProps) {
if (prevProps.rootMargin !== this.props.rootMargin || prevProps.root !== this.props.root || prevProps.threshold !== this.props.threshold || prevProps.skip !== this.props.skip || prevProps.trackVisibility !== this.props.trackVisibility || prevProps.delay !== this.props.delay) {
this.unobserve();
this.observeNode();
}
}
componentWillUnmount() {
this.unobserve();
}
observeNode() {
if (!this.node || this.props.skip) return;
const {
threshold,
root,
rootMargin,
trackVisibility,
delay,
fallbackInView
} = this.props;
this._unobserveCb = observe(
this.node,
this.handleChange,
{
threshold,
root,
rootMargin,
// @ts-ignore
trackVisibility,
// @ts-ignore
delay
},
fallbackInView
);
}
unobserve() {
if (this._unobserveCb) {
this._unobserveCb();
this._unobserveCb = null;
}
}
render() {
const { children } = this.props;
if (typeof children === "function") {
const { inView, entry } = this.state;
return children({ inView, entry, ref: this.handleNode });
}
const {
as,
triggerOnce,
threshold,
root,
rootMargin,
onChange,
skip,
trackVisibility,
delay,
initialInView,
fallbackInView,
...props
} = this.props;
return React.createElement(
as || "div",
{ ref: this.handleNode, ...props },
children
);
}
};
function useInView({
threshold,
delay,
trackVisibility,
rootMargin,
root,
triggerOnce,
skip,
initialInView,
fallbackInView,
onChange
} = {}) {
var _a;
const [ref, setRef] = React2.useState(null);
const callback = React2.useRef(onChange);
const [state, setState] = React2.useState({
inView: !!initialInView,
entry: void 0
});
callback.current = onChange;
React2.useEffect(
() => {
if (skip || !ref) return;
let unobserve;
unobserve = observe(
ref,
(inView, entry) => {
setState({
inView,
entry
});
if (callback.current) callback.current(inView, entry);
if (entry.isIntersecting && triggerOnce && unobserve) {
unobserve();
unobserve = void 0;
}
},
{
root,
rootMargin,
threshold,
// @ts-ignore
trackVisibility,
// @ts-ignore
delay
},
fallbackInView
);
return () => {
if (unobserve) {
unobserve();
}
};
},
// We break the rule here, because we aren't including the actual `threshold` variable
// eslint-disable-next-line react-hooks/exhaustive-deps
[
// If the threshold is an array, convert it to a string, so it won't change between renders.
Array.isArray(threshold) ? threshold.toString() : threshold,
ref,
root,
rootMargin,
triggerOnce,
skip,
trackVisibility,
fallbackInView,
delay
]
);
const entryTarget = (_a = state.entry) == null ? void 0 : _a.target;
const previousEntryTarget = React2.useRef(void 0);
if (!ref && entryTarget && !triggerOnce && !skip && previousEntryTarget.current !== entryTarget) {
previousEntryTarget.current = entryTarget;
setState({
inView: !!initialInView,
entry: void 0
});
}
const result = [setRef, state.inView, state.entry];
result.ref = result[0];
result.inView = result[1];
result.entry = result[2];
return result;
}
export {
InView,
defaultFallbackInView,
observe,
useInView
};
//# sourceMappingURL=react-intersection-observer.js.map
File diff suppressed because one or more lines are too long
+1119
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
import {
require_react
} from "./chunk-W4EHDCLL.js";
import "./chunk-EWTE5DHJ.js";
export default require_react();
//# sourceMappingURL=react.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
# React + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+38
View File
@@ -0,0 +1,38 @@
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/images/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Crop Compass</title>
<link
href="https://cdn.jsdelivr.net/npm/flowbite@2.5.1/dist/flowbite.min.css"
rel="stylesheet"
/>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/flowbite@2.5.1/dist/flowbite.min.js"></script>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
+48
View File
@@ -0,0 +1,48 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@reduxjs/toolkit": "^2.2.7",
"@splinetool/react-spline": "^4.0.0",
"apexcharts": "^4.5.0",
"chart.js": "^4.4.8",
"flowbite": "^2.5.1",
"framer-motion": "^12.4.7",
"react": "^18.3.1",
"react-apexcharts": "^1.7.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"react-intersection-observer": "^9.15.1",
"react-player": "^2.16.0",
"react-redux": "^9.1.2",
"react-router-dom": "^6.26.1",
"react-typewriter-effect": "^1.1.0",
"socket.io-client": "^4.7.5",
"axios": "^1.6.8",
"sha1": "^1.1.1"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"eslint": "^9.9.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"postcss": "^8.4.45",
"tailwindcss": "^3.4.10",
"vite": "^5.4.1"
}
}
+6
View File
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

+1
View File
@@ -0,0 +1 @@
<svg viewBox="-2.4 -2.4 28.80 28.80" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="3.2640000000000002"> <title></title> <g id="Complete"> <g id="add-square"> <g> <rect data-name="--Rectangle" fill="none" height="20" id="_--Rectangle" rx="2" ry="2" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" width="20" x="2" y="2"></rect> <line fill="none" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" x1="15.5" x2="8.5" y1="12" y2="12"></line> <line fill="none" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" x1="12" x2="12" y1="15.5" y2="8.5"></line> </g> </g> </g> </g><g id="SVGRepo_iconCarrier"> <title></title> <g id="Complete"> <g id="add-square"> <g> <rect data-name="--Rectangle" fill="none" height="20" id="_--Rectangle" rx="2" ry="2" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" width="20" x="2" y="2"></rect> <line fill="none" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" x1="15.5" x2="8.5" y1="12" y2="12"></line> <line fill="none" stroke="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4" x1="12" x2="12" y1="15.5" y2="8.5"></line> </g> </g> </g> </g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+12
View File
@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
<defs>
</defs>
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)" >
<path d="M 37.712 41.541 c -2.437 -10.14 2.919 -19.609 8.772 -25.137 c -6.221 11.54 -7.41 20.104 -3.461 33.177 l 2.29 -0.854 c -0.882 -2.464 -1.413 -4.873 -1.685 -7.241 c 8.23 -2.355 13.883 -7.209 15.231 -15.926 C 59.796 13.651 52.042 6.72 43.718 0.117 c 3.04 9.758 -11.581 17.964 -10.296 30.949 c 0.271 2.741 0.697 5.33 1.326 7.825" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(127,178,65); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
<path d="M 34.069 30.999 c 0.917 -12.923 13.599 -21.098 9.649 -30.883 c 1.394 8.216 -9.771 12.38 -12.663 22.195 c -1.575 5.836 -1.151 11.452 3.693 16.579 C 34.119 36.396 33.937 33.751 34.069 30.999 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(113,156,64); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
<polygon points="68.77,61.09 70.46,47.61 43.69,47.61 19.54,47.61 21.23,61.09 " style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(160,126,99); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) "/>
<polyline points="63.11,61.09 59.5,90 44.01,90 30.5,90 26.89,61.09 " style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(160,126,99); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) "/>
<polygon points="62.61,65.09 63.11,61.09 26.89,61.09 27.39,65.09 " style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(145,107,77); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

View File
+101
View File
@@ -0,0 +1,101 @@
import { useDispatch, useSelector } from "react-redux";
import "./App.css";
// import Navbar from "./components/Navbar";
import Navbar2 from "./components/Navbar2";
import { useEffect, useState } from "react";
import { userSliceActions } from "./store/userSlice";
import { Outlet } from "react-router-dom";
import { BACKEND_URL } from "./constants";
// Simple LanguageSwitcher component
function LanguageSwitcher({ language, setLanguage }) {
return (
<select
value={language}
onChange={(e) => {
setLanguage(e.target.value);
localStorage.setItem("language", e.target.value);
}}
className="absolute top-2 right-2 p-1 rounded border"
aria-label="Select language"
>
<option value="en">English</option>
<option value="hi">Hindi (ि)</option>
<option value="mr">Marathi (मर)</option>
<option value="fr">Français</option>
{/* Add more languages here */}
</select>
);
}
function App() {
const user = useSelector((store) => store.user);
const dispatch = useDispatch();
const loader = useSelector((store) => store.loader);
// Language state, initialized from localStorage or default to 'en'
const [language, setLanguage] = useState(
localStorage.getItem("language") || "en"
);
console.log("Current language:", language);
useEffect(() => {
async function initialiseUser() {
if (user.role === "unloggeduser") {
const responce = await fetch(`${BACKEND_URL}/api/v1/getuser`, {
method: "GET",
credentials: "include",
});
const userData = await responce.json();
dispatch(userSliceActions.addUser(userData.data));
}
}
initialiseUser();
}, []);
return (
<>
<div className="w-full h-auto flex-col relative">
{/* 2. Language Switcher visible on all pages */}
<LanguageSwitcher language={language} setLanguage={setLanguage} />
{/* 3. Pass language as prop to Navbar2 and Outlet if needed */}
<Outlet context={{ language }} />
<div
className={`${
loader ? "block" : "hidden"
} absolute w-full h-full bg-black opacity-50 top-0 left-0`}
>
<div className="text-center my-96">
<div role="status">
<svg
aria-hidden="true"
className="inline w-12 h-12 text-gray-200 animate-spin dark:text-gray-600 fill-blue-900"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
</div>
</div>
</div>
</>
);
}
export default App;
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
const LanguageSwitcher = ({ currentLanguage, onChangeLanguage }) => (
<select value={currentLanguage} onChange={e => onChangeLanguage(e.target.value)}>
<option value="en">English</option>
<option value="hi">Hindi (ि)</option>
<option value="mr">Marathi (मर)</option>
<option value="fr">French (Français)</option>
{/* Add more languages as needed */}
</select>
);
export default LanguageSwitcher;
+11
View File
@@ -0,0 +1,11 @@
import React from "react";
const Container = ({ children }) => {
return (
<>
<div className="w-full max-h-screen">{children}</div>
</>
);
};
export default Container;
+66
View File
@@ -0,0 +1,66 @@
import { useEffect, useState } from "react";
import Td from "./Td";
import Loader from "./Loader";
import { useGetFarmsQuery } from "../store/api/farmApi";
const FarmList = () => {
// const [data, setData] = useState([]);
// const [loading, setLoading] = useState(true);
const { data: farms, error, isLoading } = useGetFarmsQuery();
console.log(farms);
// useEffect(() => {
// fetch("http://localhost:8000/api/v1/farm", {
// credentials: "include",
// method: "GET",
// headers: { "Content-Type": "application/json" },
// })
// .then((response) => response.json())
// .then((data) => setData(data))
// .then(setLoading(false))
// .catch((error) => console.error(error));
// }, []);
return (
<div className="relative overflow-x-auto shadow-md sm:rounded-lg">
{isLoading ? (
<Loader></Loader>
) : (
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="px-6 py-3">
Farm name
</th>
<th scope="col" className="px-6 py-3">
Location
</th>
<th scope="col" className="px-6 py-3">
Type
</th>
<th scope="col" className="px-6 py-3">
Size (acres)
</th>
<th scope="col" className="px-6 py-3">
Action
</th>
</tr>
</thead>
<tbody>
{farms && farms.length > 0 ? (
farms.map((item) => <Td key={item.id} children={item} />)
) : (
<tr>
<td colSpan={5} className="text-center">
No data available
</td>
</tr>
)}
</tbody>
</table>
)}
</div>
);
};
export default FarmList;
+38
View File
@@ -0,0 +1,38 @@
import React from 'react'
function FileInput() {
const handleFileChange= () => {
const fileInput = document.getElementById("file_input");
const file = fileInput.files[0];
if (!file) {
alert("Please select a file!");
return;
}
const formData = new FormData();
formData.append("file", file);
// Send to backend
fetch("http://your-backend-url.com/upload", {
method: "POST",
body: formData,
})
.then((response) => response.json())
.then((data) => console.log("File uploaded successfully:", data))
.catch((error) => console.error("Upload failed:", error));
}
return (
<div className=' pt-24'>
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white" for="file_input">Upload file</label>
<input class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
id="file_input"
type="file"
onChange={handleFileChange} />
</div>
)
}
export default FileInput
+29
View File
@@ -0,0 +1,29 @@
const Laoder = () => {
return (
<div className="w-full bg-white rounded-lg shadow p-4">
<div class="flex items-center justify-center w-full h-56 border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
<div role="status">
<svg
aria-hidden="true"
class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
);
};
export default Laoder;
+29
View File
@@ -0,0 +1,29 @@
const Loader = () => {
return (
<div className="w-full bg-white rounded-lg shadow p-4">
<div class="flex items-center justify-center w-full h-56 border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
<div role="status">
<svg
aria-hidden="true"
class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
);
};
export default Loader;
+69
View File
@@ -0,0 +1,69 @@
import { Link } from "react-router-dom";
const Logs = () => {
return (
<>
<div className="relative overflow-y-hidden">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 border">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="px-6 py-3">
Product name
</th>
<th scope="col" className="px-6 py-3">
Color
</th>
<th scope="col" className="px-6 py-3">
Category
</th>
<th scope="col" className="px-6 py-3">
Price
</th>
</tr>
</thead>
<tbody>
<tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 border-gray-200">
<th
scope="row"
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
>
Apple MacBook Pro 17"
</th>
<td className="px-6 py-4">Silver</td>
<td className="px-6 py-4">Laptop</td>
<td className="px-6 py-4">$2999</td>
</tr>
<tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 border-gray-200">
<th
scope="row"
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
>
Microsoft Surface Pro
</th>
<td className="px-6 py-4">White</td>
<td className="px-6 py-4">Laptop PC</td>
<td className="px-6 py-4">$1999</td>
</tr>
<tr className="bg-white dark:bg-gray-800">
<th
scope="row"
className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
>
Magic Mouse 2
</th>
<td className="px-6 py-4">Black</td>
<td className="px-6 py-4">Accessories</td>
<td className="px-6 py-4">$99</td>
</tr>
</tbody>{" "}
</table>{" "}
<Link to="/logs" className="text-[#2323FF] pl-5">
<hr />
View all Logs
</Link>
</div>
</>
);
};
export default Logs;

Some files were not shown because too many files have changed in this diff Show More