Commit e8822483 authored by Gamage B.G.J's avatar Gamage B.G.J

Merge branch 'feature/marks-calculator' into 'master'

Feature/marks calculator

See merge request !13
parents d073333a a248a8bd
{ {
"cSpell.words": [ "cSpell.words": [
"formik",
"Janith", "Janith",
"leaderboard", "leaderboard",
"SLIIT" "SLIIT"
......
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
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"torch": "^0.2.7",
"uuid": "^9.0.0" "uuid": "^9.0.0"
} }
}, },
...@@ -58,6 +59,22 @@ ...@@ -58,6 +59,22 @@
"node": ">= 0.6" "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": { "node_modules/anymatch": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
...@@ -190,6 +207,29 @@ ...@@ -190,6 +207,29 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/chokidar": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
...@@ -343,6 +383,14 @@ ...@@ -343,6 +383,14 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" "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": { "node_modules/etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
...@@ -526,6 +574,17 @@ ...@@ -526,6 +574,17 @@
"node": ">= 0.4.0" "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": { "node_modules/has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
...@@ -1343,6 +1402,17 @@ ...@@ -1343,6 +1402,17 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" "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": { "node_modules/supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
...@@ -1373,6 +1443,18 @@ ...@@ -1373,6 +1443,18 @@
"node": ">=0.6" "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": { "node_modules/touch": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
...@@ -1522,6 +1604,16 @@ ...@@ -1522,6 +1604,16 @@
"negotiator": "0.6.3" "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": { "anymatch": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
...@@ -1629,6 +1721,25 @@ ...@@ -1629,6 +1721,25 @@
"get-intrinsic": "^1.0.2" "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": { "chokidar": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
...@@ -1743,6 +1854,11 @@ ...@@ -1743,6 +1854,11 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" "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": { "etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
...@@ -1887,6 +2003,14 @@ ...@@ -1887,6 +2003,14 @@
"function-bind": "^1.1.1" "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": { "has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
...@@ -2489,6 +2613,14 @@ ...@@ -2489,6 +2613,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": { "supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
...@@ -2510,6 +2642,14 @@ ...@@ -2510,6 +2642,14 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" "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": { "touch": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"torch": "^0.2.7",
"uuid": "^9.0.0" "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 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
...@@ -4,10 +4,17 @@ import dotenv from "dotenv"; ...@@ -4,10 +4,17 @@ import dotenv from "dotenv";
import express from "express"; import express from "express";
import mongoose from "mongoose"; 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 routes
import curriculumRoutes from "./routes/curriculum.routes.js"; import curriculumRoutes from "./routes/curriculum.routes.js";
import feedbackRoutes from "./routes/feedback.routes.js"; import feedbackRoutes from "./routes/feedback.routes.js";
import leaderboardRoutes from "./routes/leaderboard.routes.js"; import leaderboardRoutes from "./routes/leaderboard.routes.js";
import marksCalculatorRoutes from "./routes/marksCalculator.routes.js";
import translateRoutes from "./routes/translate.routes.js"; import translateRoutes from "./routes/translate.routes.js";
import tutorialRoutes from "./routes/tutorial.routes.js"; import tutorialRoutes from "./routes/tutorial.routes.js";
import userRoutes from "./routes/user.routes.js"; import userRoutes from "./routes/user.routes.js";
...@@ -33,6 +40,7 @@ app.use("/rest_node/tutorial", tutorialRoutes); ...@@ -33,6 +40,7 @@ app.use("/rest_node/tutorial", tutorialRoutes);
app.use("/rest_node/user-progress", userProgressRoutes); app.use("/rest_node/user-progress", userProgressRoutes);
app.use("/rest_node/feedback", feedbackRoutes); app.use("/rest_node/feedback", feedbackRoutes);
app.use("/rest_node/leaderboard", leaderboardRoutes); 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 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; const PORT = process.env.PORT || 5000;
......
// import { useMemo } from 'react'; import { useMemo } from 'react';
// material-ui // material-ui
import { Theme } from '@mui/material/styles';
import { Box, useMediaQuery } from '@mui/material'; import { Box, useMediaQuery } from '@mui/material';
import { Theme } from '@mui/material/styles';
// project import // project import
import Search from './Search'; import Localization from './Localization';
import Message from './Message'; import Message from './Message';
import Profile from './Profile';
// import Localization from './Localization';
import Notification from './Notification'; import Notification from './Notification';
import Profile from './Profile';
import Search from './Search';
// import Customization from './Customization'; // import Customization from './Customization';
import MobileSection from './MobileSection'; import MobileSection from './MobileSection';
// import MegaMenuSection from './MegaMenuSection'; // import MegaMenuSection from './MegaMenuSection';
...@@ -23,13 +23,12 @@ import { MenuOrientation } from 'types/config'; ...@@ -23,13 +23,12 @@ import { MenuOrientation } from 'types/config';
// ==============================|| HEADER - CONTENT ||============================== // // ==============================|| HEADER - CONTENT ||============================== //
const HeaderContent = () => { const HeaderContent = () => {
// const { i18n, menuOrientation } = useConfig(); const { i18n, menuOrientation } = useConfig();
const { menuOrientation } = useConfig();
const downLG = useMediaQuery((theme: Theme) => theme.breakpoints.down('lg')); const downLG = useMediaQuery((theme: Theme) => theme.breakpoints.down('lg'));
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
// const localization = useMemo(() => <Localization />, [i18n]); const localization = useMemo(() => <Localization />, [i18n]);
// const megaMenu = useMemo(() => <MegaMenuSection />, []); // const megaMenu = useMemo(() => <MegaMenuSection />, []);
...@@ -38,7 +37,7 @@ const HeaderContent = () => { ...@@ -38,7 +37,7 @@ const HeaderContent = () => {
{menuOrientation === MenuOrientation.HORIZONTAL && !downLG && <DrawerHeader open={true} />} {menuOrientation === MenuOrientation.HORIZONTAL && !downLG && <DrawerHeader open={true} />}
{!downLG && <Search />} {!downLG && <Search />}
{/* {!downLG && megaMenu} */} {/* {!downLG && megaMenu} */}
{/* {!downLG && localization} */} {!downLG && localization}
{downLG && <Box sx={{ width: '100%', ml: 1 }} />} {downLG && <Box sx={{ width: '100%', ml: 1 }} />}
<Notification /> <Notification />
......
...@@ -3,6 +3,7 @@ import { MouseEvent, useMemo, useState } from 'react'; ...@@ -3,6 +3,7 @@ import { MouseEvent, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
Button, Button,
Dialog,
IconButton, IconButton,
Stack, Stack,
Table, Table,
...@@ -32,7 +33,9 @@ import { ...@@ -32,7 +33,9 @@ import {
import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons'; import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons';
//types //types
import AlertTutorialDelete from 'sections/parameters/tutorial-management/AlertTutorialDelete'; import { PopupTransition } from 'components/@extended/Transitions';
import AddEditCurriculum from 'sections/parameters/curriculum-management/AddEditCurriculum';
import AlertCurriculumDelete from 'sections/parameters/curriculum-management/AlertCurriculumDelete';
import { ReactTableProps, curriculumProps, dataProps } from './types/types'; import { ReactTableProps, curriculumProps, dataProps } from './types/types';
// ==============================|| REACT TABLE ||============================== // // ==============================|| REACT TABLE ||============================== //
...@@ -205,8 +208,8 @@ const List = () => { ...@@ -205,8 +208,8 @@ const List = () => {
color="error" color="error"
onClick={(e: MouseEvent<HTMLButtonElement>) => { onClick={(e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); e.stopPropagation();
// setTutorialId(row.values.id) setCurriculumId(row.values._id)
// setOpenAlert(true) setOpenAlert(true)
}} }}
> >
<DeleteTwoTone twoToneColor={theme.palette.error.main} /> <DeleteTwoTone twoToneColor={theme.palette.error.main} />
...@@ -232,9 +235,7 @@ const List = () => { ...@@ -232,9 +235,7 @@ const List = () => {
//alert model //alert model
const [openAlert, setOpenAlert] = useState(false); const [openAlert, setOpenAlert] = useState(false);
// const [curriculumId, setCurriculumId] = useState<number | null>(null) const [curriculumId, setCurriculumId] = useState<number | string | undefined>(undefined)
const curriculumId : number | null = null
const handleAlertClose = () => { const handleAlertClose = () => {
setOpenAlert(!openAlert); setOpenAlert(!openAlert);
...@@ -246,8 +247,21 @@ const List = () => { ...@@ -246,8 +247,21 @@ const List = () => {
<ScrollX> <ScrollX>
<ReactTable columns={columns} data={data} handleAddEdit={handleAddEdit} /> <ReactTable columns={columns} data={data} handleAddEdit={handleAddEdit} />
</ScrollX> </ScrollX>
{/* add / edit curriculum dialog */}
<Dialog
maxWidth="sm"
TransitionComponent={PopupTransition}
keepMounted
fullWidth
onClose={handleAddEdit}
open={addEdit}
sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }}
aria-describedby="alert-dialog-slide-description"
>
<AddEditCurriculum curriculum={curriculum} onCancel={handleAddEdit} />
</Dialog>
{/* alert model */} {/* alert model */}
{!curriculum && <AlertTutorialDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={curriculumId} />} {!curriculum && <AlertCurriculumDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={curriculumId} />}
</MainCard> </MainCard>
</> </>
) )
......
...@@ -3,6 +3,7 @@ import { MouseEvent, useMemo, useState } from 'react'; ...@@ -3,6 +3,7 @@ import { MouseEvent, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
Button, Button,
Dialog,
IconButton, IconButton,
Stack, Stack,
Table, Table,
...@@ -18,6 +19,7 @@ import { ...@@ -18,6 +19,7 @@ import {
import { Cell, Column, HeaderGroup, Row, useFilters, useGlobalFilter, usePagination, useTable } from 'react-table'; import { Cell, Column, HeaderGroup, Row, useFilters, useGlobalFilter, usePagination, useTable } from 'react-table';
// project import // project import
import { PopupTransition } from 'components/@extended/Transitions';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX'; import ScrollX from 'components/ScrollX';
import { CSVExport, EmptyTable, TablePagination } from 'components/third-party/ReactTable'; import { CSVExport, EmptyTable, TablePagination } from 'components/third-party/ReactTable';
...@@ -32,6 +34,7 @@ import { ...@@ -32,6 +34,7 @@ import {
import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons'; import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons';
//types //types
import AddEditTutorial from 'sections/parameters/tutorial-management/AddEditTutorial';
import AlertTutorialDelete from 'sections/parameters/tutorial-management/AlertTutorialDelete'; import AlertTutorialDelete from 'sections/parameters/tutorial-management/AlertTutorialDelete';
import { ReactTableProps, dataProps, tutorialProps } from './types/types'; import { ReactTableProps, dataProps, tutorialProps } from './types/types';
...@@ -201,8 +204,8 @@ const List = () => { ...@@ -201,8 +204,8 @@ const List = () => {
color="error" color="error"
onClick={(e: MouseEvent<HTMLButtonElement>) => { onClick={(e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); e.stopPropagation();
// setTutorialId(row.values.id) setTutorialId(row.values._id)
// setOpenAlert(true) setOpenAlert(true)
}} }}
> >
<DeleteTwoTone twoToneColor={theme.palette.error.main} /> <DeleteTwoTone twoToneColor={theme.palette.error.main} />
...@@ -228,9 +231,7 @@ const List = () => { ...@@ -228,9 +231,7 @@ const List = () => {
//alert model //alert model
const [openAlert, setOpenAlert] = useState(false); const [openAlert, setOpenAlert] = useState(false);
// const [tutorialId, setTutorialId] = useState<number | null>(null) const [tutorialId, setTutorialId] = useState<number | string | undefined>(undefined)
const tutorialId: number | null = null
const handleAlertClose = () => { const handleAlertClose = () => {
setOpenAlert(!openAlert); setOpenAlert(!openAlert);
...@@ -242,6 +243,19 @@ const List = () => { ...@@ -242,6 +243,19 @@ const List = () => {
<ScrollX> <ScrollX>
<ReactTable columns={columns} data={data} handleAddEdit={handleAddEdit} /> <ReactTable columns={columns} data={data} handleAddEdit={handleAddEdit} />
</ScrollX> </ScrollX>
{/* add / edit tutorial dialog */}
<Dialog
maxWidth="sm"
TransitionComponent={PopupTransition}
keepMounted
fullWidth
onClose={handleAddEdit}
open={addEdit}
sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }}
aria-describedby="alert-dialog-slide-description"
>
<AddEditTutorial tutorial={tutorial} onCancel={handleAddEdit} />
</Dialog>
{/* alert model */} {/* alert model */}
{!tutorial && <AlertTutorialDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={tutorialId} />} {!tutorial && <AlertTutorialDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={tutorialId} />}
</MainCard> </MainCard>
......
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;
...@@ -13,7 +13,7 @@ interface Props { ...@@ -13,7 +13,7 @@ interface Props {
title: string; title: string;
open: boolean; open: boolean;
handleClose: (status: boolean) => void; handleClose: (status: boolean) => void;
deleteId: number | null; deleteId: number | string | undefined;
} }
// ==============================|| Curriculum - DELETE ||============================== // // ==============================|| Curriculum - DELETE ||============================== //
......
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;
...@@ -13,7 +13,7 @@ interface Props { ...@@ -13,7 +13,7 @@ interface Props {
title: string; title: string;
open: boolean; open: boolean;
handleClose: (status: boolean) => void; handleClose: (status: boolean) => void;
deleteId: number | null; deleteId: number | string | undefined;
} }
// ==============================|| Tutorial - DELETE ||============================== // // ==============================|| Tutorial - DELETE ||============================== //
......
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