Commit 740491ac authored by Ridma Dilshan's avatar Ridma Dilshan

Merge branch 'master' into IT20005276

parents 22c86490 e8822483
{
"cSpell.words": [
"formik",
"Janith",
"leaderboard",
"SLIIT"
]
}
\ No newline at end of file
import Curriculum from '../models/curriculum.model.js';
export const getAllCurriculums = async (req, res) => {
try {
const curriculums = await Curriculum.find();
res.status(200).json(curriculums);
} catch (error) {
res.status(500).json({ message: error.message });
}
}
export const getCurriculumById = async (req, res) => {
const { id } = req.params;
try {
const curriculum = await Curriculum.findById(id);
res.status(200).json(curriculum);
} catch (error) {
res.status(404).json({ message: 'Curriculum not found' });
}
}
export const createCurriculum = async (req, res) => {
const curriculumData = req.body;
try {
const newCurriculum = new Curriculum(curriculumData);
await newCurriculum.save();
res.status(201).json(newCurriculum);
} catch (error) {
res.status(400).json({ message: error.message });
}
}
export const updateCurriculum = async (req, res) => {
const { id } = req.params;
const updatedCurriculum = req.body;
try {
const result = await Curriculum.findByIdAndUpdate(id, updatedCurriculum, { new: true });
res.status(200).json(result);
} catch (error) {
res.status(404).json({ message: 'Curriculum not found' });
}
}
export const deleteCurriculum = async (req, res) => {
const { id } = req.params;
try {
await Curriculum.findByIdAndDelete(id);
res.status(200).json({ message: 'Curriculum deleted successfully' });
} catch (error) {
res.status(404).json({ message: 'Curriculum not found' });
}
}
import Feedback from '../models/feedback.model.js';
export const createFeedback = async (req, res) => {
const { userId, entityId, rating, comment } = req.body;
try {
const feedback = new Feedback({
userId,
entityId,
rating,
comment
});
await feedback.save();
res.status(201).json({ code: '01', message: 'Feedback submitted successfully' });
} catch (error) {
res.status(500).json({ code: '00', message: 'Error submitting feedback' });
}
}
export const getFeedbackForEntity = async (req, res) => {
const entityId = req.params.entityId;
try {
const feedback = await Feedback.find({ entityId }).populate('userId', 'firstName lastName');
res.status(200).json(feedback);
} catch (error) {
res.status(500).json({ code: '00', message: 'Error fetching feedback' });
}
}
import UserProgress from '../models/userProgress.model.js';
export const getGlobalLeaderboard = async (req, res) => {
try {
const userProgressList = await UserProgress.find({}, 'userId curriculumId tutorialProgress.marks').populate('userId', 'firstName lastName');
// Aggregate user progress data to calculate total marks and progress
const leaderboard = userProgressList.map(userProgress => {
const totalMarks = userProgress.curriculumId.reduce((total, curriculum) => {
return total + curriculum.tutorialProgress.reduce((totalTutMarks, tutorial) => {
return totalTutMarks + (tutorial.completed ? tutorial.marks : 0);
}, 0);
}, 0);
const totalTutorials = userProgress.curriculumId.reduce((totalTut, curriculum) => {
return totalTut + curriculum.tutorialProgress.length;
}, 0);
return {
user: userProgress.userId,
totalMarks,
totalTutorials
};
});
// Sort leaderboard based on total marks
leaderboard.sort((a, b) => b.totalMarks - a.totalMarks);
res.status(200).json(leaderboard);
} catch (error) {
res.status(500).json({ message: 'Error fetching global leaderboard' });
}
}
import { exec } from "child_process";
export const marksCalculator = async (req, res) => {
const imageData = req.file.buffer.toString('base64');
const targetClass = req.body.class;
const { curriculumIndex, tutorialIndex } = req.params;
const status = "";
// console.log(curriculumIndex, tutorialIndex);
try {
if (curriculumIndex == 1 && tutorialIndex == 1) {
// Run Python script to perform prediction
const pythonProcess = exec('python prediction_config/C1T1/predict.py', (error, stdout, stderr) => {
if (error) {
console.error(error);
return res.status(500).json({ error: 'An error occurred' });
}
const [predicted_class_name, confidence] = stdout.trim().split(',');
const parsedConfidence = parseFloat(confidence).toFixed(2);
let status = "";
if (predicted_class_name === targetClass && parsedConfidence > 85) {
status = "pass";
} else {
status = "fail";
}
res.status(200).json({
code: "01",
result: {
predicted_class_name,
confidence: parsedConfidence,
status
}
});
});
pythonProcess.stdin.write(`${imageData}\n${targetClass}`);
pythonProcess.stdin.end();
} else {
return res.status(400).json({ code: "02", message: "Curriculum Index or Tutorial Index Invalid" })
}
} catch (error) {
res.status(500).json({ code: "00", message: "Something went wrong" })
}
}
\ No newline at end of file
import Tutorial from '../models/tutorial.model.js';
export const getAllTutorials = async (req, res) => {
try {
const tutorials = await Tutorial.find();
res.status(200).json(tutorials);
} catch (error) {
res.status(500).json({ message: error.message });
}
}
export const getTutorialById = async (req, res) => {
const { id } = req.params;
try {
const tutorial = await Tutorial.findById(id);
res.status(200).json(tutorial);
} catch (error) {
res.status(404).json({ message: 'Tutorial not found' });
}
}
export const createTutorial = async (req, res) => {
const tutorialData = req.body;
try {
const newTutorial = new Tutorial(tutorialData);
await newTutorial.save();
res.status(201).json(newTutorial);
} catch (error) {
res.status(400).json({ message: error.message });
}
}
export const updateTutorial = async (req, res) => {
const { id } = req.params;
const updatedTutorial = req.body;
try {
const result = await Tutorial.findByIdAndUpdate(id, updatedTutorial, { new: true });
res.status(200).json(result);
} catch (error) {
res.status(404).json({ message: 'Tutorial not found' });
}
}
export const deleteTutorial = async (req, res) => {
const { id } = req.params;
try {
await Tutorial.findByIdAndDelete(id);
res.status(200).json({ message: 'Tutorial deleted successfully' });
} catch (error) {
res.status(404).json({ message: 'Tutorial not found' });
}
}
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import mongoose from 'mongoose';
import nodemailer from "nodemailer";
import User from '../models/user.model.js';
export const signIn = async (req, res) => {
......@@ -128,53 +127,11 @@ export const updateUser = async (req, res) => {
return res.status(404).json({ code: "02", message: `No User for this id: ${id}` });
}
if (data.type == "buyer" || data.type == "admin") {
const updateUser = { ...data, _id: id }
await User.findByIdAndUpdate(id, updateUser, { new: true })
res.status(200);
res.json({ code: "01", result: updateUser })
} else if (data.type == "trader") {
var password = Math.random().toString(36).slice(-8);
const hashPassword = await bcrypt.hash(password, 12)
const updateUser = { ...data, password: hashPassword, _id: id }
await User.findByIdAndUpdate(id, updateUser, { new: true })
//call email service
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: process.env.MAIL_USERNAME,
pass: process.env.MAIL_PASSWORD,
clientId: process.env.OAUTH_CLIENTID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
refreshToken: process.env.OAUTH_REFRESH_TOKEN
}
});
let mailOptions = {
from: "janithgamage1.ed@gmail.com",
to: updateUser.email,
subject: 'Shop House Project',
text: `You are Successfully Approved, you're username: ${updateUser.email} , you're password : ${password}`
};
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});
res.status(200);
res.json({ code: "01", result: updateUser })
}
const updateUser = { ...data, _id: id }
await User.findByIdAndUpdate(id, updateUser, { new: true })
res.status(200);
res.json({ code: "01", result: updateUser })
} catch (error) {
......@@ -193,7 +150,7 @@ export const deleteUser = async (req, res) => {
await User.findByIdAndDelete(id);
res.status(200);
res.json({ code: "01", "message": "User Deleted Successfully" });
res.json({ code: "01", result: id, "message": "User Deleted Successfully" });
} catch (error) {
res.status(404);
res.json({ code: "00", "message": error.message });
......
import UserProgress from '../models/userProgress.model.js';
export const getUserProgress = async (req, res) => {
const userId = req.params.userId;
try {
const userProgress = await UserProgress.findOne({ userId }).populate('curriculumId tutorialProgress.tutorialId');
res.status(200).json(userProgress);
} catch (error) {
res.status(500).json({ message: error.message });
}
}
export const updateUserProgress = async (req, res) => {
const userId = req.params.userId;
const { curriculumId, tutorialId, completed, marks } = req.body;
try {
let userProgress = await UserProgress.findOne({ userId });
if (!userProgress) {
userProgress = new UserProgress({ userId });
}
const curriculumProgress = userProgress.curriculumId.find(prog => prog.curriculumId.equals(curriculumId));
if (!curriculumProgress) {
userProgress.curriculumId.push({ curriculumId });
}
const tutorialProgress = curriculumProgress.tutorialProgress.find(prog => prog.tutorialId.equals(tutorialId));
if (!tutorialProgress) {
curriculumProgress.tutorialProgress.push({ tutorialId, completed });
} else {
tutorialProgress.completed = completed;
}
userProgress.marks = marks;
await userProgress.save();
res.status(200).json(userProgress);
} catch (error) {
res.status(500).json({ message: error.message });
}
}
import mongoose from "mongoose";
const tutorialSchema = new mongoose.Schema({
tutorialCode: String,
tutorialTitle: String,
tutorialImage: String,
// Additional fields for tutorial content
});
const curriculumSchema = new mongoose.Schema({
curriculumCode: String,
curriculumLevel: String,
curriculumName: String,
curriculumImage: String,
tutorials: [tutorialSchema], // Embed tutorials as subdocuments
// Additional fields for curriculum details
status: {
type: Number,
default: 1, // Default status as active (1)
},
createdBy: String,
updatedBy: String,
createdAt: {
type: Date,
default: new Date(),
},
updatedAt: {
type: Date,
default: new Date(),
},
});
const Curriculum = mongoose.model("Curriculum", curriculumSchema);
export default Curriculum;
import mongoose from 'mongoose';
const feedbackSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User' // Reference to the User model
},
entityId: {
type: mongoose.Schema.Types.ObjectId,
required: true, // This could be the tutorial or curriculum ID
ref: 'Tutorial' // Reference to the Tutorial model (or Curriculum model)
},
rating: {
type: Number,
required: true
},
comment: String,
createdAt: {
type: Date,
default: new Date()
}
});
const Feedback = mongoose.model('Feedback', feedbackSchema);
export default Feedback;
import mongoose from "mongoose";
const taskItemSchema = new mongoose.Schema({
title: String,
description: String,
howToDo: String,
referenceImage: String,
referenceVideo: String,
// Additional fields for task items
});
const tutorialSchema = new mongoose.Schema({
tutorialCode: String,
tutorialTitle: String,
tutorialImage: String,
taskItems: [taskItemSchema], // Embed task items as subdocuments
// Additional fields for tutorial details
status: {
type: Number,
default: 1, // Default status as active (1)
},
createdBy: String,
updatedBy: String,
createdAt: {
type: Date,
default: new Date(),
},
updatedAt: {
type: Date,
default: new Date(),
},
});
const Tutorial = mongoose.model("Tutorial", tutorialSchema);
export default Tutorial;
import mongoose from "mongoose";
const userProgressSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User' // Reference to the User model
},
curriculumId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Curriculum' // Reference to the Curriculum model
},
tutorialProgress: [
{
tutorialId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Tutorial' // Reference to the Tutorial model
},
completed: {
type: Boolean,
default: false
}
}
],
marks: {
type: Number,
default: 0
}
});
const UserProgress = mongoose.model("UserProgress", userProgressSchema);
export default UserProgress;
......@@ -20,6 +20,7 @@
"nodemailer": "^6.9.1",
"nodemon": "^2.0.22",
"react-mic": "^12.4.6",
"torch": "^0.2.7",
"uuid": "^9.0.0"
}
},
......@@ -59,6 +60,22 @@
"node": ">= 0.6"
}
},
"node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
......@@ -191,6 +208,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
"dependencies": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/chalk/node_modules/supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
......@@ -344,6 +384,14 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
......@@ -527,6 +575,17 @@
"node": ">= 0.4.0"
}
},
"node_modules/has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
......@@ -1411,6 +1470,17 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
......@@ -1441,6 +1511,18 @@
"node": ">=0.6"
}
},
"node_modules/torch": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/torch/-/torch-0.2.7.tgz",
"integrity": "sha512-yTv7qWKGg00hMDv0pyBgRjubbf4eygzzrjKPKRC9rbPCKBF0jd+cxnzIoN+pCHgGf2EQbd0jGyy1X7h5BIqjEA==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"dependencies": {
"chalk": "^1.1.3"
},
"engines": {
"node": ">= 0.8.4"
}
},
"node_modules/touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
......@@ -1590,6 +1672,16 @@
"negotiator": "0.6.3"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="
},
"anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
......@@ -1697,6 +1789,25 @@
"get-intrinsic": "^1.0.2"
}
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
},
"dependencies": {
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="
}
}
},
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
......@@ -1811,6 +1922,11 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
......@@ -1955,6 +2071,14 @@
"function-bind": "^1.1.1"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
......@@ -2611,6 +2735,14 @@
}
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
......@@ -2632,6 +2764,14 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"torch": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/torch/-/torch-0.2.7.tgz",
"integrity": "sha512-yTv7qWKGg00hMDv0pyBgRjubbf4eygzzrjKPKRC9rbPCKBF0jd+cxnzIoN+pCHgGf2EQbd0jGyy1X7h5BIqjEA==",
"requires": {
"chalk": "^1.1.3"
}
},
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
......
......@@ -22,6 +22,7 @@
"nodemailer": "^6.9.1",
"nodemon": "^2.0.22",
"react-mic": "^12.4.6",
"torch": "^0.2.7",
"uuid": "^9.0.0"
}
}
import sys
import io
import base64
import torch
import torchvision.transforms as transforms
from PIL import Image
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
class theCNN(nn.Module):
def __init__(self):
super().__init__()
self.conv01 = nn.Conv2d(
in_channels=1,
out_channels=10,
kernel_size=5,
stride=1,
padding=1
)
self.dropout1 = nn.Dropout(0.2) # Add dropout layer
self.conv02 = nn.Conv2d(
in_channels=10,
out_channels=20,
kernel_size=5,
stride=1,
padding=1
)
self.dropout2 = nn.Dropout(0.2) # Add dropout layer
expectedSize = np.floor((73+2*0-1)/1) + 1
expectedSize = 20*int(expectedSize**2)
self.fc01 = nn.Linear(expectedSize, 50)
self.output = nn.Linear(50, 16)
def forward(self, x):
# convo -> maxpool -> relu
x = F.relu(F.max_pool2d(self.conv01(x), 2))
# convo -> maxpool -> relu
x = F.relu(F.max_pool2d(self.conv02(x), 2))
nUnits = x.shape.numel()/x.shape[0]
x = x.view(-1, int(nUnits))
x = F.relu(self.fc01(x))
return torch.softmax(self.output(x), axis=1)
# Load the mapping dictionary
class_mapping = {
0: 'Eight',
1: 'Eleven',
2: 'Fifty',
3: 'Five',
4: 'Four',
5: 'Fourteen',
6: 'Nine',
7: 'One',
8: 'Seven',
9: 'Six',
10: 'Ten',
11: 'Thirteen',
12: 'Thirty',
13: 'Three',
14: 'Twenty',
15: 'Two'
}
# Load the trained model
model = theCNN() # Instantiate your model class
model.load_state_dict(torch.load(
'D:/SLIIT_Y4_Research_Module/Research/Project/2023-029/Project/Backend/Server_Node/prediction_config/C1T1/trained_model_modified.pth', map_location=torch.device('cpu')))
model.eval()
# Read image data and target class from standard input
input_data = sys.stdin.readlines()
image_data = input_data[0].strip().encode() # Convert to bytes
target_class = input_data[1].strip()
# Preprocess the image
# image_data = base64.b64decode(sys.argv[1])
# image = Image.open(io.BytesIO(image_data))
image = Image.open(io.BytesIO(base64.b64decode(image_data)))
transform = transforms.Compose([
transforms.Resize((300, 300)),
transforms.Grayscale(num_output_channels=1),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5], std=[0.5]),
])
image_tensor = transform(image).unsqueeze(0)
# Predict the class
with torch.no_grad():
outputs = model(image_tensor)
predicted_class = torch.argmax(outputs[0]).item()
confidence = outputs[0][predicted_class].item()
# Get the predicted class name using the mapping dictionary
predicted_class_name = class_mapping[predicted_class]
# Calculate similarity or confidence percentage
# target_class = sys.argv[2].lower() # Class name passed from the API
similarity = 100 * confidence
print(f"{predicted_class_name},{similarity:.2f}")
import express from "express";
import {
createCurriculum,
deleteCurriculum,
getAllCurriculums,
getCurriculumById,
updateCurriculum
} from "../controllers/curriculum.controller.js";
const router = express.Router();
router.get('/', getAllCurriculums);
router.get('/:id', getCurriculumById);
router.post('/', createCurriculum);
router.put('/:id', updateCurriculum);
router.delete('/:id', deleteCurriculum);
export default router;
import express from 'express';
import { createFeedback, getFeedbackForEntity } from '../controllers/feedback.controller.js';
const router = express.Router();
router.post('/', createFeedback);
router.get('/:entityId', getFeedbackForEntity);
export default router;
import express from 'express';
import { getGlobalLeaderboard } from '../controllers/leaderboard.controller.js';
const router = express.Router();
router.get('/global', getGlobalLeaderboard);
export default router;
import express from "express";
import multer from "multer";
import { marksCalculator } from "../controllers/marksCalculator.controller.js";
// Set up storage for uploaded images
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
const router = express.Router();
router.post('/curriculum/:curriculumIndex/tutorial/:tutorialIndex', upload.single('image'), marksCalculator)
export default router;
\ No newline at end of file
import express from "express";
import {
getAllTutorials,
getTutorialById,
createTutorial,
updateTutorial,
deleteTutorial
} from "../controllers/tutorial.controller.js";
const router = express.Router();
router.get('/', getAllTutorials);
router.get('/:id', getTutorialById);
router.post('/', createTutorial);
router.put('/:id', updateTutorial);
router.delete('/:id', deleteTutorial);
export default router;
......@@ -7,7 +7,7 @@ router.post('/sign-in', signIn)
router.post('/sign-up', signUp)
router.get('/all', getUsers);
router.get('/:id', getUser);
router.get('/test/:userType', getUserAccordingToType);
router.get('/all/type/:userType', getUserAccordingToType);
router.put('/:id', updateUser);
router.delete('/:id', deleteUser);
......
import express from "express";
import { getUserProgress, updateUserProgress } from "../controllers/userProgress.controller.js";
const router = express.Router();
router.get('/:userId', getUserProgress);
router.post('/:userId', updateUserProgress);
export default router;
......@@ -4,9 +4,21 @@ import dotenv from "dotenv";
import express from "express";
import mongoose from "mongoose";
import multer from "multer";
// Set up storage for uploaded images
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
//import routes
import curriculumRoutes from "./routes/curriculum.routes.js";
import feedbackRoutes from "./routes/feedback.routes.js";
import leaderboardRoutes from "./routes/leaderboard.routes.js";
import marksCalculatorRoutes from "./routes/marksCalculator.routes.js";
import translateRoutes from "./routes/translate.routes.js";
import tutorialRoutes from "./routes/tutorial.routes.js";
import userRoutes from "./routes/user.routes.js";
import userProgressRoutes from "./routes/userProgress.routes.js";
dotenv.config();
const app = express();
......@@ -23,6 +35,12 @@ app.get("/", (req, res) => {
//implement routes
app.use("/rest_node/ssl", translateRoutes);
app.use("/rest_node/user", userRoutes);
app.use("/rest_node/curriculum", curriculumRoutes);
app.use("/rest_node/tutorial", tutorialRoutes);
app.use("/rest_node/user-progress", userProgressRoutes);
app.use("/rest_node/feedback", feedbackRoutes);
app.use("/rest_node/leaderboard", leaderboardRoutes);
app.use("/rest_node/marks-calculator", marksCalculatorRoutes);
const CONNECTION_URL = `mongodb+srv://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@researchmanagement-appl.vzhn4.mongodb.net/?retryWrites=true&w=majority`;
const PORT = process.env.PORT || 5000;
......
......@@ -56,15 +56,17 @@ export const JWTProvider = ({ children }: { children: React.ReactElement }) => {
const init = async () => {
try {
const serviceToken = window.localStorage.getItem('serviceToken');
console.log(verifyToken(serviceToken!));
if (serviceToken && verifyToken(serviceToken)) {
setSession(serviceToken);
const response = await axios.get('/api/account/me');
const { user } = response.data;
// const response = await axios.get('/api/account/me');
// const { user } = response.data;
dispatch({
type: LOGIN,
payload: {
isLoggedIn: true,
user
// user
}
});
} else {
......
// import { useMemo } from 'react';
import { useMemo } from 'react';
// material-ui
import { Theme } from '@mui/material/styles';
import { Box, useMediaQuery } from '@mui/material';
import { Theme } from '@mui/material/styles';
// project import
import Search from './Search';
import Localization from './Localization';
import Message from './Message';
import Profile from './Profile';
// import Localization from './Localization';
import Notification from './Notification';
import Profile from './Profile';
import Search from './Search';
// import Customization from './Customization';
import MobileSection from './MobileSection';
// import MegaMenuSection from './MegaMenuSection';
......@@ -23,13 +23,12 @@ import { MenuOrientation } from 'types/config';
// ==============================|| HEADER - CONTENT ||============================== //
const HeaderContent = () => {
// const { i18n, menuOrientation } = useConfig();
const { menuOrientation } = useConfig();
const { i18n, menuOrientation } = useConfig();
const downLG = useMediaQuery((theme: Theme) => theme.breakpoints.down('lg'));
// eslint-disable-next-line react-hooks/exhaustive-deps
// const localization = useMemo(() => <Localization />, [i18n]);
const localization = useMemo(() => <Localization />, [i18n]);
// const megaMenu = useMemo(() => <MegaMenuSection />, []);
......@@ -38,7 +37,7 @@ const HeaderContent = () => {
{menuOrientation === MenuOrientation.HORIZONTAL && !downLG && <DrawerHeader open={true} />}
{!downLG && <Search />}
{/* {!downLG && megaMenu} */}
{/* {!downLG && localization} */}
{!downLG && localization}
{downLG && <Box sx={{ width: '100%', ml: 1 }} />}
<Notification />
......
......@@ -117,7 +117,14 @@ const application: NavItemType = {
// title: <FormattedMessage id="learning-list" />,
// type: 'item',
// url: '/learning-management/list',
// },
// },
{
id: 'learning-dashboard',
title: <FormattedMessage id="learning-dashboard" />,
type: 'item',
url: '/learning-management/dashboard',
breadcrumbs: false
},
{
id: 'learning-curriculums',
title: <FormattedMessage id="learning-curriculums" />,
......
// material-ui
import { Grid } from '@mui/material';
// third-party
// project import
import WelcomeBanner from 'sections/learning-management/WelcomeBanner';
// assets
//types
// ==============================|| Dashboard ||============================== //
const Dashboard = () => {
return (
<Grid container rowSpacing={4.5} columnSpacing={3}>
<Grid item xs={12}>
<WelcomeBanner />
</Grid>
</Grid>
)
}
export default Dashboard;
......@@ -18,9 +18,7 @@ import ScrollX from 'components/ScrollX';
const List = () => {
return (
<MainCard content={false}>
<ScrollX>
{/* content here */}
<h1>Sample Page 2</h1>
<ScrollX>
</ScrollX>
</MainCard>
)
......
......@@ -17,9 +17,7 @@ import ScrollX from 'components/ScrollX';
const List = () => {
return (
<MainCard content={false}>
<ScrollX>
{/* content here */}
<h1>Sample Page</h1>
<ScrollX>
</ScrollX>
</MainCard>
)
......
// material-ui
// third-party
// project import
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
// assets
//types
// ==============================|| List ||============================== //
const List = () => {
return (
<MainCard content={false}>
<ScrollX>
</ScrollX>
</MainCard>
)
}
export default List;
// material-ui
// third-party
// project import
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
// assets
//types
// ==============================|| List ||============================== //
const List = () => {
return (
<MainCard content={false}>
<ScrollX>
</ScrollX>
</MainCard>
)
}
export default List;
import { Column } from 'react-table';
export interface dataProps {
_id: number | string | undefined;
curriculumCode: String;
curriculumLevel: String;
curriculumName: String;
curriculumImage: String;
tutorials: tutorialItemProps[];
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
}
export interface ReactTableProps {
columns: Column[]
data: dataProps[]
handleAddEdit: () => void
}
export interface curriculumProps {
_id: number | string | undefined;
curriculumCode: String;
curriculumLevel: String;
curriculumName: String;
curriculumImage: String;
tutorials: tutorialItemProps[];
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
}
export interface tutorialItemProps {
_id: number | string | undefined;
tutorialCode: String;
tutorialTitle: String;
tutorialImage: String;
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
}
export interface taskItemProps {
_id: number | string | undefined;
title: String;
description: String;
howToDo: String;
referenceImage: String;
referenceVideo: String;
}
\ No newline at end of file
import { Column } from 'react-table';
export interface dataProps {
_id: number | string | undefined;
tutorialCode: String;
tutorialTitle: String;
tutorialImage: String;
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
}
export interface ReactTableProps {
columns: Column[]
data: dataProps[]
handleAddEdit: () => void
}
export interface tutorialProps {
_id: number | string | undefined;
tutorialCode: String;
tutorialTitle: String;
tutorialImage: String;
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
}
export interface taskItemProps {
_id: number | string | undefined;
title: String;
description: String;
howToDo: String;
referenceImage: String;
referenceVideo: String;
}
\ No newline at end of file
......@@ -29,8 +29,15 @@ const MemberManagementList = Loadable(lazy(() => import('pages/member-management
// render - user management page
const UserManagementList = Loadable(lazy(() => import('pages/user-management/list/list')));
// render - learning management page
// const LearningManagementList = Loadable(lazy(() => import('pages/learning-management/list/list')));
// render - ssl translate process page
const SSLTranslateProcess = Loadable(lazy(() => import('pages/ssl-translate/process/process')));
// render - learning-management pages
const LearningDashboard = Loadable(lazy(() => import('pages/learning-management/dashboard')));
const LearningCurriculums = Loadable(lazy(() => import('pages/learning-management/learning-curriculums/list/list')));
const LearningCurriculumsSubscribed = Loadable(lazy(() => import('pages/learning-management/learning-curriculums-subscribed/list/list')));
const LearningLeadBoard = Loadable(lazy(() => import('pages/learning-management/learning-lead-board/list/list')));
const LearningFeedBack = Loadable(lazy(() => import('pages/learning-management/learning-feedback/list/list')));
// render - parameter curriculum management page
const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/curriculum-management/list/list')));
......@@ -38,8 +45,7 @@ const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/cur
// render - parameter tutorial management page
const TutorialManagementList = Loadable(lazy(() => import('pages/parameter/tutorial-management/list/list')));
// render - ssl translate process page
const SSLTranslateProcess = Loadable(lazy(() => import('pages/ssl-translate/process/process')));
// render - audio-detection page
const AudioDetection = Loadable(lazy(() => import('pages/emotion-detection/emotion-audio-detection/list/list')));
......@@ -47,11 +53,7 @@ const AudioDetection = Loadable(lazy(() => import('pages/emotion-detection/emoti
// render - video-detection page
const VideoDetection = Loadable(lazy(() => import('pages/emotion-detection/emotion-video-detection/list/list')));
// render - learning-curriculums-subscribed page
const LearningCurriculumsSubscribed = Loadable(lazy(() => import('pages/learning-management/learning-curriculums-subscribed/list/list')));
// render - learning-curriculums page
const LearningCurriculums = Loadable(lazy(() => import('pages/learning-management/learning-curriculums/list/list')));
// ==============================|| MAIN ROUTING ||============================== //
......@@ -120,6 +122,10 @@ const MainRoutes = {
{
path: 'learning-management',
children: [
{
path: 'dashboard',
element: <LearningDashboard />
},
{
path: 'curriculums',
element: <LearningCurriculums />
......@@ -127,6 +133,14 @@ const MainRoutes = {
{
path: 'curriculums-subscribed',
element: <LearningCurriculumsSubscribed />
},
{
path: 'lead-board',
element: <LearningLeadBoard />
},
{
path: 'feedback',
element: <LearningFeedBack />
}
]
},
......
import { useState } from 'react';
// material-ui
import { AvatarGroup, Box, Button, Divider, Grid, LinearProgress, Stack, Tooltip, Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
// project import
import Avatar from 'components/@extended/Avatar';
import MainCard from 'components/MainCard';
// assets
import { PlusOutlined } from '@ant-design/icons';
import Reader from 'assets/images/analytics/reader.svg';
// types
import { ThemeDirection } from 'types/config';
const avatarImage = require.context('assets/images/users', true);
// ==============================|| READER CARD ||============================== //
function ReaderCard() {
const theme = useTheme();
const [show, setShow] = useState<boolean>(false);
return (
<Grid item xs={12}>
<Grid container>
<Grid
item
xs={12}
sm={7}
sx={{
bgcolor: `${theme.palette.primary.main}`,
position: 'relative',
p: 2.75,
borderRadius: { xs: 2, sm: '8px 0px 0px 8px' },
overflow: 'hidden'
}}
>
<Stack>
<Typography variant="h5" color="white">
What would you want to learn today
</Typography>
<Typography color={theme.palette.grey[0]} variant="caption" sx={{ maxWidth: '55%', pt: 1 }}>
Your learning capacity is 80% as daily analytics
</Typography>
<Typography variant="h4" color="white" sx={{ pt: 8, pb: 1, zIndex: 1 }}>
35% Completed
</Typography>
<Box sx={{ maxWidth: '60%' }}>
<LinearProgress variant="determinate" color="success" value={35} />
</Box>
<Box
sx={{
position: 'absolute',
bottom: -7,
right: 0,
...(theme.direction === ThemeDirection.RTL && { transform: { xs: 'rotateY(180deg)', sm: 'inherit' } })
}}
>
<img alt="reder" src={Reader} />
</Box>
</Stack>
</Grid>
<Grid item xs={12} sm={5}>
<MainCard sx={{ borderRadius: { xs: 2, sm: '0px 8px 8px 0px' }, height: '100%', mt: { xs: 2.5, sm: 0 } }}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Stack>
<Typography>Get started with new basic skills</Typography>
<Typography color="textSecondary" sx={{ pt: 1 }}>
Last Date 5th Nov 2020
</Typography>
<Divider sx={{ pt: 3, width: '100%' }} />
</Stack>
</Grid>
<Grid item xs={12}>
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={3}>
<Box sx={{ width: 186 }}>
<Tooltip
open={show}
placement="top-end"
title={
<AvatarGroup max={10}>
<Avatar alt="Agnes Walker" src={avatarImage(`./avatar-4.png`)} />
<Avatar alt="Trevor Henderson" src={avatarImage(`./avatar-5.png`)} />
<Avatar alt="Jone Doe" src={avatarImage(`./avatar-6.png`)} />
</AvatarGroup>
}
>
<AvatarGroup
sx={{
'& .MuiAvatarGroup-avatar': { bgcolor: theme.palette.primary.main, cursor: 'pointer' },
justifyContent: 'start',
'& .MuiAvatar-root': { width: 32, height: 32, fontSize: '0.875rem', bgcolor: 'secondary.400' }
}}
max={4}
componentsProps={{
additionalAvatar: {
onMouseEnter: () => {
setShow(true);
},
onMouseLeave: () => {
setShow(false);
}
}
}}
>
<Avatar alt="Remy Sharp" src={avatarImage(`./avatar-1.png`)} />
<Avatar alt="Travis Howard" src={avatarImage(`./avatar-2.png`)} />
<Avatar alt="Cindy Baker" src={avatarImage(`./avatar-3.png`)} />
<Avatar alt="Agnes Walker" src={avatarImage(`./avatar-4.png`)} />
<Avatar alt="Trevor Henderson" src={avatarImage(`./avatar-5.png`)} />
</AvatarGroup>
</Tooltip>
</Box>
<Button size="small" variant="contained" sx={{ minWidth: 'max-content', p: 1.5 }}>
<PlusOutlined />
</Button>
</Stack>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" color="secondary">
Chrome fixed the bug several versions ago, thus rendering this...
</Typography>
</Grid>
</Grid>
</MainCard>
</Grid>
</Grid>
</Grid>
);
}
export default ReaderCard;
// material-ui
import { Box, Button, Grid, Stack, Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
// project import
import MainCard from 'components/MainCard';
//asset
import WelcomeImageArrow from 'assets/images/analytics/welcome-arrow.png';
import WelcomeImage from 'assets/images/analytics/welcome-banner.png';
// types
import { ThemeDirection } from 'types/config';
import { useNavigate } from 'react-router';
// ==============================|| ANALYTICS - WELCOME ||============================== //
const WelcomeBanner = () => {
const theme = useTheme();
const navigate = useNavigate()
return (
<MainCard
border={false}
sx={{
background:
theme.direction === ThemeDirection.RTL
? `linear-gradient(60.38deg, ${theme.palette.primary.lighter} 114%, ${theme.palette.primary.light} 34.42%, ${theme.palette.primary.main} 60.95%, ${theme.palette.primary.dark} 84.83%, ${theme.palette.primary.darker} 104.37%)`
: `linear-gradient(250.38deg, ${theme.palette.primary.lighter} 2.39%, ${theme.palette.primary.light} 34.42%, ${theme.palette.primary.main} 60.95%, ${theme.palette.primary.dark} 84.83%, ${theme.palette.primary.darker} 104.37%)`
}}
>
<Grid container>
<Grid item md={6} sm={6} xs={12}>
<Stack spacing={2} sx={{ padding: 3.4 }}>
<Typography variant="h2" color={theme.palette.background.paper}>
Welcome to SSL Sign Language Learning Platform
</Typography>
<Typography variant="h6" color={theme.palette.background.paper}>
Welcome to the SSL Sign Language Learning Platform. Your path to mastering sign language starts here. Whether you're a beginner or refining skills, our platform offers diverse courses with step-by-step tutorials. Begin your journey to fluent communication in SSL Sign Language today.
</Typography>
<Box>
<Button
variant="outlined"
color="secondary"
sx={{ color: theme.palette.background.paper, borderColor: theme.palette.background.paper }}
onClick={() => {navigate('/learning-management/curriculums')}}
>
View full Courses
</Button>
</Box>
</Stack>
</Grid>
<Grid item sm={6} xs={12} sx={{ display: { xs: 'none', sm: 'initial' } }}>
<Stack sx={{ position: 'relative', pr: { sm: 3, md: 8 } }} justifyContent="center" alignItems="flex-end">
<img src={WelcomeImage} alt="Welcome" />
<Box sx={{ position: 'absolute', bottom: 0, right: '10%' }}>
<img src={WelcomeImageArrow} alt="Welcome Arrow" />
</Box>
</Stack>
</Grid>
</Grid>
</MainCard>
);
};
export default WelcomeBanner;
import { useState } from 'react';
// material-ui
import {
Button,
DialogActions,
DialogContent,
DialogTitle,
Divider,
Grid,
Stack,
Tooltip
} from '@mui/material';
// import { useTheme } from '@mui/material/styles';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
// third-party
import { Form, FormikProvider, FormikValues, useFormik } from 'formik';
import _ from 'lodash';
import * as Yup from 'yup';
// project imports
import IconButton from 'components/@extended/IconButton';
// assets
import { DeleteFilled } from '@ant-design/icons';
import AlertCurriculumDelete from './AlertCurriculumDelete';
// types
// constant
const getInitialValues = (curriculum: FormikValues | null) => {
const newCurriculum = {
_id: undefined,
}
if (curriculum) {
return _.merge({}, newCurriculum, curriculum);
}
return newCurriculum;
};
// ==============================|| CUSTOMER ADD / EDIT ||============================== //
export interface Props {
curriculum?: {
_id: number | string | undefined;
curriculumCode: String;
curriculumLevel: String;
curriculumName: String;
curriculumImage: String;
tutorials: tutorialItemProps[];
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
};
onCancel: () => void;
}
export interface tutorialItemProps {
_id: number | string | undefined;
tutorialCode: String;
tutorialTitle: String;
tutorialImage: String;
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
}
export interface taskItemProps {
_id: number | string | undefined;
title: String;
description: String;
howToDo: String;
referenceImage: String;
referenceVideo: String;
}
const AddEditCurriculum = ({ curriculum, onCancel }: Props) => {
// const theme = useTheme();
const isCreating = !curriculum;
const CurriculumSchema = Yup.object().shape({});
const [openAlert, setOpenAlert] = useState(false);
const handleAlertClose = () => {
setOpenAlert(!openAlert);
onCancel();
};
const formik = useFormik({
initialValues: getInitialValues(curriculum!),
validationSchema: CurriculumSchema,
enableReinitialize: true,
onSubmit: (values, { setSubmitting, resetForm }) => {
try {
if (curriculum) {
// PUT API
} else {
// POST API
}
resetForm()
setSubmitting(false);
onCancel();
} catch (error) {
console.error(error);
}
}
});
// const { errors, touched, handleSubmit, isSubmitting, getFieldProps } = formik;
const { handleSubmit, isSubmitting } = formik;
return (
<>
<FormikProvider value={formik}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
<DialogTitle>{curriculum ? 'Edit Curriculum' : 'New Curriculum'}</DialogTitle>
<Divider />
<DialogContent sx={{ p: 2.5 }}>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
<Grid container spacing={3}>
</Grid>
</Grid>
</Grid>
</DialogContent>
<Divider />
<DialogActions sx={{ p: 2.5 }}>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
{!isCreating && (
<Tooltip title="Delete Tutorial" placement="top">
<IconButton onClick={() => setOpenAlert(true)} size="large" color="error">
<DeleteFilled />
</IconButton>
</Tooltip>
)}
</Grid>
<Grid item>
<Stack direction="row" spacing={2} alignItems="center">
<Button color="error" onClick={onCancel}>
Cancel
</Button>
<Button type="submit" variant="contained" disabled={isSubmitting}>
{curriculum ? 'Edit' : 'Add'}
</Button>
</Stack>
</Grid>
</Grid>
</DialogActions>
</Form>
</LocalizationProvider>
</FormikProvider>
{!isCreating && <AlertCurriculumDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={curriculum._id} />}
</>
);
};
export default AddEditCurriculum;
// material-ui
import { Button, Dialog, DialogContent, Stack, Typography } from '@mui/material';
// project import
import Avatar from 'components/@extended/Avatar';
import { PopupTransition } from 'components/@extended/Transitions';
// assets
import { DeleteFilled } from '@ant-design/icons';
// types
interface Props {
title: string;
open: boolean;
handleClose: (status: boolean) => void;
deleteId: number | string | undefined;
}
// ==============================|| Curriculum - DELETE ||============================== //
export default function AlertCurriculumDelete({ title, open, handleClose, deleteId }: Props) {
// const dispatch = useDispatch();
return (
<Dialog
open={open}
onClose={() => handleClose(false)}
keepMounted
TransitionComponent={PopupTransition}
maxWidth="xs"
aria-labelledby="column-delete-title"
aria-describedby="column-delete-description"
>
<DialogContent sx={{ mt: 2, my: 1 }}>
<Stack alignItems="center" spacing={3.5}>
<Avatar color="error" sx={{ width: 72, height: 72, fontSize: '1.75rem' }}>
<DeleteFilled />
</Avatar>
<Stack spacing={2}>
<Typography variant="h4" align="center">
Are you sure you want to delete?
</Typography>
</Stack>
<Stack direction="row" spacing={2} sx={{ width: 1 }}>
<Button fullWidth onClick={() => handleClose(false)} color="secondary" variant="outlined">
Cancel
</Button>
<Button fullWidth color="error" variant="contained" onClick={() => {
// dispatch(deleteNutrition(deleteId!))
handleClose(true)
}} autoFocus>
Delete
</Button>
</Stack>
</Stack>
</DialogContent>
</Dialog >
);
}
import { useState } from 'react';
// material-ui
import {
Button,
DialogActions,
DialogContent,
DialogTitle,
Divider,
Grid,
Stack,
Tooltip
} from '@mui/material';
// import { useTheme } from '@mui/material/styles';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
// third-party
import { Form, FormikProvider, FormikValues, useFormik } from 'formik';
import _ from 'lodash';
import * as Yup from 'yup';
// project imports
import IconButton from 'components/@extended/IconButton';
// assets
import { DeleteFilled } from '@ant-design/icons';
import AlertTutorialDelete from './AlertTutorialDelete';
// types
// constant
const getInitialValues = (tutorial: FormikValues | null) => {
const newTutorial = {
_id: undefined,
}
if (tutorial) {
return _.merge({}, newTutorial, tutorial);
}
return newTutorial;
};
// ==============================|| CUSTOMER ADD / EDIT ||============================== //
export interface Props {
tutorial?: {
_id: number | string | undefined
tutorialCode: String;
tutorialTitle: String;
tutorialImage: String;
status: Number;
createdBy: String;
updatedBy: String;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
};
onCancel: () => void;
}
export interface taskItemProps {
_id: number | string | undefined;
title: String;
description: String;
howToDo: String;
referenceImage: String;
referenceVideo: String;
}
const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
// const theme = useTheme();
const isCreating = !tutorial;
const TutorialSchema = Yup.object().shape({});
const [openAlert, setOpenAlert] = useState(false);
const handleAlertClose = () => {
setOpenAlert(!openAlert);
onCancel();
};
const formik = useFormik({
initialValues: getInitialValues(tutorial!),
validationSchema: TutorialSchema,
enableReinitialize: true,
onSubmit: (values, { setSubmitting, resetForm }) => {
try {
if (tutorial) {
// PUT API
} else {
// POST API
}
resetForm()
setSubmitting(false);
onCancel();
} catch (error) {
console.error(error);
}
}
});
// const { errors, touched, handleSubmit, isSubmitting, getFieldProps } = formik;
const { handleSubmit, isSubmitting} = formik;
return (
<>
<FormikProvider value={formik}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
<DialogTitle>{tutorial ? 'Edit Tutorial' : 'New Tutorial'}</DialogTitle>
<Divider />
<DialogContent sx={{ p: 2.5 }}>
<Grid container spacing={3}>
<Grid item xs={12} md={12}>
<Grid container spacing={3}>
</Grid>
</Grid>
</Grid>
</DialogContent>
<Divider />
<DialogActions sx={{ p: 2.5 }}>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
{!isCreating && (
<Tooltip title="Delete Tutorial" placement="top">
<IconButton onClick={() => setOpenAlert(true)} size="large" color="error">
<DeleteFilled />
</IconButton>
</Tooltip>
)}
</Grid>
<Grid item>
<Stack direction="row" spacing={2} alignItems="center">
<Button color="error" onClick={onCancel}>
Cancel
</Button>
<Button type="submit" variant="contained" disabled={isSubmitting}>
{tutorial ? 'Edit' : 'Add'}
</Button>
</Stack>
</Grid>
</Grid>
</DialogActions>
</Form>
</LocalizationProvider>
</FormikProvider>
{!isCreating && <AlertTutorialDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={tutorial._id} />}
</>
);
};
export default AddEditTutorial;
// material-ui
import { Button, Dialog, DialogContent, Stack, Typography } from '@mui/material';
// project import
import Avatar from 'components/@extended/Avatar';
import { PopupTransition } from 'components/@extended/Transitions';
// assets
import { DeleteFilled } from '@ant-design/icons';
// types
interface Props {
title: string;
open: boolean;
handleClose: (status: boolean) => void;
deleteId: number | string | undefined;
}
// ==============================|| Tutorial - DELETE ||============================== //
export default function AlertTutorialDelete({ title, open, handleClose, deleteId }: Props) {
// const dispatch = useDispatch();
return (
<Dialog
open={open}
onClose={() => handleClose(false)}
keepMounted
TransitionComponent={PopupTransition}
maxWidth="xs"
aria-labelledby="column-delete-title"
aria-describedby="column-delete-description"
>
<DialogContent sx={{ mt: 2, my: 1 }}>
<Stack alignItems="center" spacing={3.5}>
<Avatar color="error" sx={{ width: 72, height: 72, fontSize: '1.75rem' }}>
<DeleteFilled />
</Avatar>
<Stack spacing={2}>
<Typography variant="h4" align="center">
Are you sure you want to delete?
</Typography>
</Stack>
<Stack direction="row" spacing={2} sx={{ width: 1 }}>
<Button fullWidth onClick={() => handleClose(false)} color="secondary" variant="outlined">
Cancel
</Button>
<Button fullWidth color="error" variant="contained" onClick={() => {
// dispatch(deleteNutrition(deleteId!))
handleClose(true)
}} autoFocus>
Delete
</Button>
</Stack>
</Stack>
</DialogContent>
</Dialog >
);
}
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import { axiosServices } from 'utils/axios';
import { dispatch } from '../index';
// types
import { DefaultRootStateProps, User } from 'types/user';
// ----------------------------------------------------------------------
const initialState: DefaultRootStateProps['user'] = {
error: null,
success: null,
users: [],
user: null,
isLoading: false
};
const slice = createSlice({
name: 'user',
initialState,
reducers: {
// TO INITIAL STATE
hasInitialState(state) {
state.error = null;
state.success = null;
state.isLoading = false;
},
// HAS ERROR
hasError(state, action) {
state.error = action.payload;
},
startLoading(state) {
state.isLoading = true;
},
finishLoading(state) {
state.isLoading = false;
},
// POST USER
addUserSuccess(state, action) {
state.users.push(action.payload.result);
state.success = "User created successfully."
},
// GET USER
fetchUserSuccess(state, action) {
state.user = action.payload.result;
state.success = null
},
// GET ALL USERS
fetchUsersSuccess(state, action) {
state.users = action.payload;
state.success = null
},
// UPDATE USER
updateUserSuccess(state, action) {
const updatedUserIndex = state.users.findIndex(user => user._id === action.payload.result._id);
if (updatedUserIndex !== -1) {
state.users[updatedUserIndex] = action.payload;
}
state.success = "User updated successfully."
},
// DELETE USER
deleteUserSuccess(state, action) {
state.users = state.users.filter(user => user._id !== action.payload.result);
state.success = "User deleted successfully."
},
}
});
// Reducer
export default slice.reducer;
// ----------------------------------------------------------------------
/**
* TO INITIAL STATE
* @returns
*/
export function toInitialState() {
return async () => {
dispatch(slice.actions.hasInitialState())
}
}
/**
* POST USER
* @param newUser
* @returns
*/
export function addUser(newUser: User) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.post('/user/sign-up', newUser);
dispatch(slice.actions.addUserSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET USER
* @param id
* @returns
*/
export function fetchUser(id: number) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get(`/user/${id}`);
dispatch(slice.actions.fetchUserSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET ALL USERS
* @param userType
* @returns
*/
export function fetchUsers(userType: string) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get(`/user/all/type/${userType}`);
dispatch(slice.actions.fetchUsersSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET ALL USERS BY TYPE
* @returns
*/
export function fetchUsersByType() {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get('/user/all');
dispatch(slice.actions.fetchUsersSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* UPDATE USER
* @param updatedUser
* @returns
*/
export function updateUser(updatedUser: User) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.put(`/user/${updatedUser._id}`, updateUser);
dispatch(slice.actions.updateUserSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* DELETE USER
* @param userId
* @returns
*/
export function deleteNutrition(userId: number) {
return async () => {
dispatch(slice.actions.startLoading());
try {
await axiosServices.delete(`/user/${userId}`);
dispatch(slice.actions.deleteUserSuccess(userId));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
// Nutritions list
// Nutrition list
export type Nutrition = {
id: string | number | undefined;
......
// User Type
export type User = {
_id: string | number | undefined;
firstName: string;
lastName: string;
email: string;
contactNumber: string;
type: string;
states: number;
createdAt: Date;
updatedAt: Date;
};
export type Users = {
_id: string | number | undefined;
firstName: string;
lastName: string;
email: string;
contactNumber: string;
type: string;
states: number;
createdAt: Date;
updatedAt: Date;
};
export interface UserStateProps {
users: Users[];
user: User | null;
error: object | string | null;
success: object | string | null;
isLoading: boolean
}
export interface DefaultRootStateProps {
user: UserStateProps;
}
\ No newline at end of file
......@@ -157,12 +157,13 @@
"curriculum-management": "Curriculum Management",
"learning-management": "Learning Management",
"learning-list": "Learning List",
"learning-curriculums": "Course",
"learning-curriculums": "Courses",
"learning-curriculums-subscribed": "My Courses",
"learning-lead-board": "Lead Board",
"learning-feedback": "Feedback",
"ssl-translate": "SSL Translate",
"emotion-detection": "Emotion Detection",
"audio-detection": "Audio Detection",
"video-detection": "Video Detection"
"video-detection": "Video Detection",
"learning-dashboard": "Dashboard"
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment