Commit 521deffe authored by Ridma Dilshan's avatar Ridma Dilshan

Fix Update

parent e319e76b
...@@ -4,5 +4,9 @@ ...@@ -4,5 +4,9 @@
"Janith", "Janith",
"leaderboard", "leaderboard",
"SLIIT" "SLIIT"
] ],
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.formatting.provider": "none"
} }
\ No newline at end of file
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "4a663198",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from PIL import Image\n",
"import numpy as np\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import LabelEncoder\n",
"from tensorflow import keras\n",
"from tensorflow.keras import layers\n",
"from keras.models import load_model"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6a893211",
"metadata": {},
"outputs": [],
"source": [
"# Set the dataset path and image size\n",
"dataset_path = \"C:/Users/himashara/Documents/signlanguage/training/\"\n",
"image_size = (480, 480) # Adjust the image size as per your requirements\n",
"\n",
"# Load and preprocess the dataset\n",
"def load_dataset():\n",
" labels = []\n",
" images = []\n",
" for label in os.listdir(dataset_path):\n",
" label_path = os.path.join(dataset_path, label)\n",
" if os.path.isdir(label_path):\n",
" for image_file in os.listdir(label_path):\n",
" image_path = os.path.join(label_path, image_file)\n",
" if os.path.isfile(image_path):\n",
" image = Image.open(image_path)\n",
" image = image.resize(image_size)\n",
" image = np.array(image)\n",
" images.append(image)\n",
" labels.append(label)\n",
" images = np.array(images)\n",
" labels = np.array(labels)\n",
" return images, labels\n",
"\n",
"images, labels = load_dataset()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ef0e4281",
"metadata": {},
"outputs": [],
"source": [
"# Encode the labels into numerical values\n",
"label_encoder = LabelEncoder()\n",
"labels = label_encoder.fit_transform(labels)\n",
"\n",
"# Split the dataset into training and testing sets\n",
"X_train, X_test, y_train, y_test = train_test_split(images, labels, test_size=0.2, random_state=42)\n",
"\n",
"# Preprocess the input data\n",
"X_train = X_train.astype(\"float32\") / 255.0\n",
"X_test = X_test.astype(\"float32\") / 255.0\n",
"num_classes = len(np.unique(labels))\n",
"y_train = keras.utils.to_categorical(y_train, num_classes)\n",
"y_test = keras.utils.to_categorical(y_test, num_classes)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "555ffeee",
"metadata": {},
"outputs": [],
"source": [
"# Define the model architecture\n",
"model = keras.Sequential([\n",
" layers.Conv2D(32, (3, 3), activation=\"relu\", input_shape=(image_size[0], image_size[1], 3)),\n",
" layers.MaxPooling2D(pool_size=(2, 2)),\n",
" layers.Flatten(),\n",
" layers.Dense(64, activation=\"relu\"),\n",
" layers.Dense(num_classes, activation=\"softmax\")\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "eb07946c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/10\n",
"22/22 [==============================] - 58s 3s/step - loss: 58.0361 - accuracy: 0.1509 - val_loss: 2.3127 - val_accuracy: 0.2059\n",
"Epoch 2/10\n",
"22/22 [==============================] - 59s 3s/step - loss: 2.3554 - accuracy: 0.2278 - val_loss: 2.0756 - val_accuracy: 0.1824\n",
"Epoch 3/10\n",
"22/22 [==============================] - 67s 3s/step - loss: 2.0049 - accuracy: 0.3195 - val_loss: 2.0513 - val_accuracy: 0.2765\n",
"Epoch 4/10\n",
"22/22 [==============================] - 65s 3s/step - loss: 1.9182 - accuracy: 0.3580 - val_loss: 1.8208 - val_accuracy: 0.3235\n",
"Epoch 5/10\n",
"22/22 [==============================] - 87s 4s/step - loss: 1.7040 - accuracy: 0.3905 - val_loss: 1.7384 - val_accuracy: 0.3294\n",
"Epoch 6/10\n",
"22/22 [==============================] - 70s 3s/step - loss: 1.6378 - accuracy: 0.4024 - val_loss: 1.9270 - val_accuracy: 0.3059\n",
"Epoch 7/10\n",
"22/22 [==============================] - 71s 3s/step - loss: 1.6423 - accuracy: 0.3905 - val_loss: 1.7039 - val_accuracy: 0.3529\n",
"Epoch 8/10\n",
"22/22 [==============================] - 66s 3s/step - loss: 1.5635 - accuracy: 0.4083 - val_loss: 1.6209 - val_accuracy: 0.3294\n",
"Epoch 9/10\n",
"22/22 [==============================] - 67s 3s/step - loss: 1.4948 - accuracy: 0.4038 - val_loss: 1.5666 - val_accuracy: 0.3765\n",
"Epoch 10/10\n",
"22/22 [==============================] - 74s 3s/step - loss: 1.4630 - accuracy: 0.4615 - val_loss: 1.5821 - val_accuracy: 0.3588\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x26f794884c0>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compile and train the model\n",
"model.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
"model.fit(X_train, y_train, batch_size=32, epochs=10, validation_data=(X_test, y_test))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "81b6613d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6/6 [==============================] - 7s 1s/step - loss: 1.5821 - accuracy: 0.3588\n",
"Test Loss: 1.5821244716644287\n",
"Test Accuracy: 0.3588235378265381\n"
]
}
],
"source": [
"# Evaluate the model on the test dataset\n",
"loss, accuracy = model.evaluate(X_test, y_test)\n",
"print(\"Test Loss:\", loss)\n",
"print(\"Test Accuracy:\", accuracy)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "65ccc47b",
"metadata": {},
"outputs": [],
"source": [
"# Save the trained model\n",
"model.save(\"letter_classification_model.h5\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0db64f31",
"metadata": {},
"outputs": [],
"source": [
"# ---------------new updated ---------------"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d0ce9c60",
"metadata": {},
"outputs": [],
"source": [
"# import os\n",
"# from PIL import Image\n",
"# import numpy as np\n",
"# from keras.models import load_model\n",
"# from sinling import SinhalaTokenizer\n",
"# from IPython.display import Image as DisplayImage, display\n",
"\n",
"# image_size = (480, 480)\n",
"\n",
"# # Dataset path\n",
"# dataset_path = \"C:/Users/himashara/Documents/signlanguage/training/\"\n",
"\n",
"# # Translation mapping from Sinhala Unicode to Singlish\n",
"# sinhala_to_singlish = {\n",
"# \"අ\": \"A\",\n",
"# \"ආ\": \"Aah\",\n",
"# \"ඇ\": \"Aeh\",\n",
"# \"ඉ\": \"Ee\",\n",
"# \"ඊ\": \"Eeh\",\n",
"# \"උ\": \"Uh\",\n",
"# \"ඌ\": \"Uhh\",\n",
"# \"එ\": \"A\",\n",
"# \"ඒ\": \"Ae\",\n",
"# \"ඔ\": \"O\",\n",
"# \"ඕ\": \"Ohh\",\n",
"# \"ක්\": \"K\",\n",
"# \"ග්\": \"Ig\",\n",
"# \"ටී\": \"Tee\",\n",
"# \"ට\": \"T\"\n",
"# }\n",
"\n",
"# # Function to retrieve the letter image\n",
"# def get_letter_image(letter):\n",
"# if os.path.exists(os.path.join(dataset_path, letter)):\n",
"# letter_path = os.path.join(dataset_path, letter)\n",
"# image_files = os.listdir(letter_path)\n",
"# image_path = os.path.join(letter_path, image_files[0]) # Assuming only one image per letter\n",
"# return Image.open(image_path)\n",
"# return None\n",
"\n",
"# # Load the pre-trained model\n",
"# model = load_model(\"letter_classification_model.h5\")\n",
"\n",
"# # Sinhala tokenizer\n",
"# tokenizer = SinhalaTokenizer()\n",
"\n",
"# # Function to preprocess Sinhala text\n",
"# def preprocess_sinhala_text(text):\n",
"# tokens = tokenizer.tokenize(text)\n",
"# return ' '.join(tokens)\n",
"\n",
"# # User input\n",
"# unicode_input = input(\"Enter a Sinhala Unicode string: \")\n",
"\n",
"# # Remove spaces from the user input\n",
"# unicode_input = unicode_input.replace(\" \", \"\")\n",
"\n",
"# # Translate Sinhala Unicode to Singlish\n",
"# singlish_input = ''.join([sinhala_to_singlish.get(c, c) for c in unicode_input])\n",
"\n",
"# # Print the translated Singlish string\n",
"# print(\"Translated Singlish string:\", singlish_input)\n",
"\n",
"# # Retrieve letter images for the Singlish input\n",
"# letter_images = []\n",
"# combined_string = \"\"\n",
"# for letter in singlish_input:\n",
"# combined_string += letter\n",
"# letter_image = get_letter_image(combined_string)\n",
"# if letter_image is not None:\n",
"# letter_image = letter_image.resize(image_size) # Adjust the size if needed\n",
"# letter_image = np.array(letter_image) / 255.0 # Normalize the image if needed\n",
"# letter_images.append(letter_image)\n",
"# combined_string = \"\"\n",
"\n",
"# # Combine the letter images into a GIF\n",
"# gif_images = [Image.fromarray(np.uint8(letter_image * 255)) for letter_image in letter_images]\n",
"\n",
"# # Save the combined images as a GIF\n",
"# output_path = \"C:/Users/himashara/Documents/signlanguage/generated-gif/generated.gif\"\n",
"# gif_images[0].save(output_path, save_all=True, append_images=gif_images[1:], loop=0, duration=1200)\n",
"\n",
"# # Display the generated GIF\n",
"# display(DisplayImage(filename=output_path))\n",
"# print(\"GIF saved successfully!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ea87d3ca",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 67,
"id": "fc22ffc8",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import tkinter as tk\n",
"from tkinter import ttk\n",
"from PIL import Image, ImageTk, ImageSequence\n",
"import numpy as np\n",
"from keras.models import load_model\n",
"from sinling import SinhalaTokenizer\n",
"\n",
"# Create Tkinter window\n",
"window = tk.Tk()\n",
"window.title(\"Sinhala to Singlish Translator\")\n",
"\n",
"# Set up the layout using Tkinter's grid system\n",
"# Step 1: Text area to enter Sinhala Unicode string\n",
"unicode_label = ttk.Label(window, text=\"Enter a Sinhala Unicode string:\")\n",
"unicode_label.grid(row=0, column=0, sticky=tk.W)\n",
"unicode_entry = ttk.Entry(window, width=30)\n",
"unicode_entry.grid(row=0, column=1, columnspan=2, pady=10)\n",
"\n",
"# Step 2: Convert button\n",
"def convert_unicode_to_singlish():\n",
" # Retrieve the Unicode input from the text entry\n",
" unicode_input = unicode_entry.get()\n",
"\n",
" # Remove spaces from the user input\n",
" unicode_input = unicode_input.replace(\" \", \"\")\n",
"\n",
" # Translate Sinhala Unicode to Singlish\n",
" singlish_input = ''.join([sinhala_to_singlish.get(c, c) for c in unicode_input])\n",
"\n",
" # Update the Singlish text display\n",
" singlish_text.delete(1.0, tk.END)\n",
" singlish_text.insert(tk.END, singlish_input)\n",
"\n",
" # Retrieve letter images for the Singlish input\n",
" letter_images = []\n",
" combined_string = \"\"\n",
" for letter in singlish_input:\n",
" combined_string += letter\n",
" letter_image = get_letter_image(combined_string)\n",
" if letter_image is not None:\n",
" letter_image = letter_image.resize(image_size) # Adjust the size if needed\n",
" letter_image = np.array(letter_image) / 255.0 # Normalize the image if needed\n",
" letter_images.append(letter_image)\n",
" combined_string = \"\"\n",
"\n",
" # Combine the letter images into a GIF\n",
" gif_images = []\n",
" for letter_image in letter_images:\n",
" image_pil = Image.fromarray((letter_image * 255).astype(np.uint8))\n",
" gif_images.append(image_pil)\n",
"\n",
" # Save the combined images as a GIF\n",
" output_path = \"C:/Users/himashara/Documents/signlanguage/generated-gif/generated.gif\"\n",
" gif_images[0].save(output_path, save_all=True, append_images=gif_images[1:], loop=0, duration=1200)\n",
"\n",
" # Display the generated GIF\n",
" display_gif(output_path)\n",
"\n",
"def clear_results():\n",
" # Clear the entered Unicode string\n",
" unicode_entry.delete(0, tk.END)\n",
"\n",
" # Clear the Singlish text display\n",
" singlish_text.delete(1.0, tk.END)\n",
"\n",
" # Clear the GIF display\n",
" gif_label.configure(image=None)\n",
" gif_label.image = None\n",
"\n",
" # Cancel the pending after() calls\n",
" window.after_cancel(gif_animation_id)\n",
"\n",
"def display_gif(output_path):\n",
" # Load the GIF and extract frames using ImageSequence module\n",
" gif_image = Image.open(output_path)\n",
" frames = [frame.copy() for frame in ImageSequence.Iterator(gif_image)]\n",
"\n",
" # Create a Tkinter label widget to display the GIF frames\n",
" global gif_label\n",
" gif_label = ttk.Label(window)\n",
" gif_label.grid(row=3, column=1, columnspan=2, pady=10)\n",
"\n",
" # Recursive function to animate the GIF frames\n",
" def animate_frame(frame_index):\n",
" # Display the current frame on the label\n",
" frame = frames[frame_index]\n",
" frame_image = ImageTk.PhotoImage(frame)\n",
" gif_label.configure(image=frame_image)\n",
" gif_label.image = frame_image\n",
"\n",
" # Calculate the index of the next frame\n",
" next_frame_index = (frame_index + 1) % len(frames)\n",
"\n",
" # Call the function again after a certain delay\n",
" global gif_animation_id\n",
" gif_animation_id = window.after(1200, animate_frame, next_frame_index)\n",
"\n",
" # Start the animation by calling the recursive function with the first frame index\n",
" animate_frame(0)\n",
"\n",
"convert_button = ttk.Button(window, text=\"Convert\", command=convert_unicode_to_singlish)\n",
"convert_button.grid(row=1, column=0, pady=10)\n",
"\n",
"clear_button = ttk.Button(window, text=\"Clear Results\", command=clear_results)\n",
"clear_button.grid(row=1, column=1, pady=10)\n",
"\n",
"# Step 3: View area to display Translated Singlish string\n",
"singlish_label = ttk.Label(window, text=\"Translated Singlish string:\")\n",
"singlish_label.grid(row=2, column=0, sticky=tk.W)\n",
"singlish_text = tk.Text(window, height=1, width=30)\n",
"singlish_text.grid(row=2, column=1, columnspan=2, pady=10)\n",
"\n",
"# Dataset path\n",
"dataset_path = \"C:/Users/himashara/Documents/signlanguage/training/\"\n",
"\n",
"# Translation mapping from Sinhala Unicode to Singlish\n",
"sinhala_to_singlish = {\n",
" \"අ\": \"A\",\n",
" \"ආ\": \"Aah\",\n",
" \"ඇ\": \"Aeh\",\n",
" \"ඉ\": \"Ee\",\n",
" \"ඊ\": \"Eeh\",\n",
" \"උ\": \"Uh\",\n",
" \"ඌ\": \"Uhh\",\n",
" \"එ\": \"A\",\n",
" \"ඒ\": \"Ae\",\n",
" \"ඔ\": \"O\",\n",
" \"ඕ\": \"Ohh\",\n",
" \"ක්\": \"K\",\n",
" \"ග්\": \"Ig\",\n",
" \"ටී\": \"Tee\",\n",
" \"ට\": \"T\"\n",
"}\n",
"\n",
"# Image size\n",
"image_size = (480, 480)\n",
"\n",
"# Function to retrieve the letter image\n",
"def get_letter_image(letter):\n",
" if os.path.exists(os.path.join(dataset_path, letter)):\n",
" letter_path = os.path.join(dataset_path, letter)\n",
" image_files = os.listdir(letter_path)\n",
" image_path = os.path.join(letter_path, image_files[0]) # Assuming only one image per letter\n",
" return Image.open(image_path)\n",
" return None\n",
"\n",
"# Load the pre-trained model\n",
"model = load_model(\"letter_classification_model.h5\")\n",
"\n",
"# Sinhala tokenizer\n",
"tokenizer = SinhalaTokenizer()\n",
"\n",
"# Function to preprocess Sinhala text\n",
"def preprocess_sinhala_text(text):\n",
" tokens = tokenizer.tokenize(text)\n",
" return ' '.join(tokens)\n",
"\n",
"# Start the Tkinter event loop\n",
"window.mainloop()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b2efcfc9",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "0e25256c",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "1028b834",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
import Curriculum from '../models/curriculum.model.js'; import Curriculum from '../models/curriculum.model.js';
import Tutorial from '../models/tutorial.model.js';
export const getAllCurriculums = async (req, res) => { export const getAllCurriculums = async (req, res) => {
try { try {
...@@ -26,17 +27,41 @@ export const createCurriculum = async (req, res) => { ...@@ -26,17 +27,41 @@ export const createCurriculum = async (req, res) => {
const curriculumData = req.body; const curriculumData = req.body;
try { try {
const newCurriculum = new Curriculum(curriculumData); const newCurriculum = new Curriculum(curriculumData);
// Calculate total tutorial mark
let totalTutorialMark = 0;
for (const tutorialId of curriculumData.tutorials) {
const tutorial = await Tutorial.findById(tutorialId);
const tutorialMarks = typeof tutorial.tutorialMarks === 'string' ? parseFloat(tutorial.tutorialMarks) : tutorial.tutorialMarks;
totalTutorialMark += isNaN(tutorialMarks) ? 0 : tutorialMarks;
}
newCurriculum.curriculumMark = totalTutorialMark;
await newCurriculum.save(); await newCurriculum.save();
res.status(201).json(newCurriculum); res.status(201).json(newCurriculum);
} catch (error) { } catch (error) {
res.status(400).json({ message: error.message }); res.status(400).json({ message: error.message });
} }
} }
export const updateCurriculum = async (req, res) => { export const updateCurriculum = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const updatedCurriculum = req.body; const updatedCurriculum = req.body;
try { try {
const curriculum = await Curriculum.findById(id);
// Calculate total tutorial mark
let totalTutorialMark = 0;
for (const tutorialId of updatedCurriculum.tutorials) {
const tutorial = await Tutorial.findById(tutorialId);
const tutorialMarks = typeof tutorial.tutorialMarks === 'string' ? parseFloat(tutorial.tutorialMarks) : tutorial.tutorialMarks;
totalTutorialMark += isNaN(tutorialMarks) ? 0 : tutorialMarks;
}
updatedCurriculum.curriculumMark = totalTutorialMark;
const result = await Curriculum.findByIdAndUpdate(id, updatedCurriculum, { new: true }); const result = await Curriculum.findByIdAndUpdate(id, updatedCurriculum, { new: true });
res.status(200).json(result); res.status(200).json(result);
} catch (error) { } catch (error) {
...@@ -48,7 +73,7 @@ export const deleteCurriculum = async (req, res) => { ...@@ -48,7 +73,7 @@ export const deleteCurriculum = async (req, res) => {
const { id } = req.params; const { id } = req.params;
try { try {
await Curriculum.findByIdAndDelete(id); await Curriculum.findByIdAndDelete(id);
res.status(200).json({ message: 'Curriculum deleted successfully' }); res.status(200).json({ _id: id, message: 'Curriculum deleted successfully' });
} catch (error) { } catch (error) {
res.status(404).json({ message: 'Curriculum not found' }); res.status(404).json({ message: 'Curriculum not found' });
} }
......
import { exec } from "child_process"; import { exec } from "child_process";
export const marksCalculator = async (req, res) => { export const marksCalculator = async (req, res) => {
try {
// console.log(req.file);
// if (!req.file || !req.body.class || !req.params.curriculumIndex || !req.params.tutorialIndex) {
// return res.status(400).json({ code: "02", message: "Missing required data" });
// }
const imageData = req.file.buffer.toString('base64'); const imageData = req.file.buffer.toString('base64');
const targetClass = req.body.class; const targetClass = req.body.class;
const { curriculumIndex, tutorialIndex } = req.params; const { curriculumIndex, tutorialIndex } = req.params;
const status = "";
// console.log(curriculumIndex, tutorialIndex);
try {
if (curriculumIndex == 1 && tutorialIndex == 1) { if (curriculumIndex == 1 && tutorialIndex == 1) {
// Run Python script to perform prediction // Run Python script to perform prediction
const pythonProcess = exec('python prediction_config/C1T1/predict.py', (error, stdout, stderr) => { const pythonProcess = exec('python prediction_config/C1T1/predict.py', (error, stdout, stderr) => {
if (error) { if (error) {
console.error(error); console.error(error);
return res.status(500).json({ error: 'An error occurred' }); return res.status(500).json({ code: '03', message: 'An error occurred while running the prediction script' });
} }
const [predicted_class_name, confidence] = stdout.trim().split(','); const [predicted_class_name, confidence] = stdout.trim().split(',');
...@@ -42,9 +45,10 @@ export const marksCalculator = async (req, res) => { ...@@ -42,9 +45,10 @@ export const marksCalculator = async (req, res) => {
pythonProcess.stdin.write(`${imageData}\n${targetClass}`); pythonProcess.stdin.write(`${imageData}\n${targetClass}`);
pythonProcess.stdin.end(); pythonProcess.stdin.end();
} else { } else {
return res.status(400).json({ code: "02", message: "Curriculum Index or Tutorial Index Invalid" }) return res.status(400).json({ code: "02", message: "Curriculum Index or Tutorial Index Invalid" });
} }
} catch (error) { } catch (error) {
res.status(500).json({ code: "00", message: "Something went wrong" }) console.error(error);
res.status(500).json({ code: "00", message: "Something went wrong" });
} }
} }
...@@ -21,32 +21,64 @@ export const getTutorialById = async (req, res) => { ...@@ -21,32 +21,64 @@ export const getTutorialById = async (req, res) => {
export const createTutorial = async (req, res) => { export const createTutorial = async (req, res) => {
const tutorialData = req.body; const tutorialData = req.body;
// Calculate total tutorial marks based on task item marks
const totalTaskMarks = tutorialData.taskItems.reduce((total, task) => {
const taskItemMark = typeof task.taskItemMark === 'string' ? parseFloat(task.taskItemMark) : task.taskItemMark;
return total + (isNaN(taskItemMark) ? 0 : taskItemMark);
}, 0);
tutorialData.tutorialMarks = totalTaskMarks;
try { try {
const newTutorial = new Tutorial(tutorialData); const newTutorial = new Tutorial(tutorialData);
await newTutorial.save(); await newTutorial.save();
res.status(201).json(newTutorial); res.status(201).json(newTutorial);
} catch (error) { } catch (error) {
res.status(400).json({ message: error.message }); res.status(500).json({ message: 'Failed to create tutorial', error: error.message });
} }
} };
export const updateTutorial = async (req, res) => { export const updateTutorial = async (req, res) => {
const { id } = req.params; const { id } = req.params;
const updatedTutorial = req.body; const updatedTutorialData = req.body;
// Calculate total tutorial marks based on updated task item marks
const totalTaskMarks = updatedTutorialData.taskItems.reduce((total, task) => {
const taskItemMark = typeof task.taskItemMark === 'string' ? parseFloat(task.taskItemMark) : task.taskItemMark;
return total + (isNaN(taskItemMark) ? 0 : taskItemMark);
}, 0);
updatedTutorialData.tutorialMarks = totalTaskMarks;
try { try {
const result = await Tutorial.findByIdAndUpdate(id, updatedTutorial, { new: true }); const tutorial = await Tutorial.findById(id);
res.status(200).json(result);
if (!tutorial) {
return res.status(404).json({ message: 'Tutorial not found' });
}
// Update the tutorial with the new data
const updatedTutorial = await Tutorial.findByIdAndUpdate(id, updatedTutorialData, { new: true });
res.status(200).json(updatedTutorial);
} catch (error) { } catch (error) {
res.status(404).json({ message: 'Tutorial not found' }); res.status(500).json({ message: error.message });
} }
} };
export const deleteTutorial = async (req, res) => { export const deleteTutorial = async (req, res) => {
const { id } = req.params; const { id } = req.params;
try { try {
const tutorial = await Tutorial.findById(id);
if (!tutorial) {
return res.status(404).json({ message: 'Tutorial not found' });
}
await Tutorial.findByIdAndDelete(id); await Tutorial.findByIdAndDelete(id);
res.status(200).json({ message: 'Tutorial deleted successfully' }); res.status(200).json({ _id: id, message: 'Tutorial deleted successfully' });
} catch (error) { } catch (error) {
res.status(404).json({ message: 'Tutorial not found' }); res.status(500).json({ message: error.message });
} }
} };
...@@ -157,3 +157,23 @@ export const deleteUser = async (req, res) => { ...@@ -157,3 +157,23 @@ export const deleteUser = async (req, res) => {
} }
} }
export const currentUser = async (req, res) => {
try {
// req.userId contains the user ID extracted from the token by the auth middleware
const userId = req.userId;
// Fetch the user account information from the database
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
// Send the user account information as a response
res.status(200).json({ user });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
}
import UserProgress from '../models/userProgress.model.js'; import Curriculum from "../models/curriculum.model.js";
import UserProgress from "../models/userProgress.model.js";
export const getUserProgress = async (req, res) => { export const subscribeCurriculum = async (req, res) => {
const userId = req.params.userId; const { userId, curriculum } = req.body;
try { try {
const userProgress = await UserProgress.findOne({ userId }).populate('curriculumId tutorialProgress.tutorialId'); // Check if the user is already subscribed to the curriculum
res.status(200).json(userProgress); let userProgress = await UserProgress.findOne({ userId });
if (!userProgress) {
// If there is no user progress record for this user, create a new one
userProgress = new UserProgress({
userId,
curriculums: [curriculum],
});
} else {
// If there is an existing user progress record, check if the curriculum already exists
const existingCurriculumIndex = userProgress.curriculums.findIndex(c => c.curriculumCode === curriculum.curriculumCode);
if (existingCurriculumIndex !== -1) {
// If the curriculum exists, update it
return res.status(400).json({ error: 'User already subscribed to this curriculum' });
} else {
// If the curriculum doesn't exist, add it to the array
userProgress.curriculums.push(curriculum);
}
}
// Update the totalCurriculumsMarks based on curriculum marks
const totalCurriculumsMarks = userProgress.curriculums.reduce((total, curriculum) => {
const curriculumMark = typeof curriculum.curriculumMark === 'string' ? parseFloat(curriculum.curriculumMark) : curriculum.curriculumMark;
return total + (isNaN(curriculumMark) ? 0 : curriculumMark);
}, 0);
userProgress.totalCurriculumsMarks = totalCurriculumsMarks;
const curriculumCode = curriculum.curriculumCode
// Now, update the curriculum collection with the subscribed user
await Curriculum.updateOne(
{ curriculumCode },
{ $addToSet: { subscribedUser: userId } }
);
// Save the user progress record
await userProgress.save();
res.status(200).json({ message: 'Curriculum subscription successful' });
} catch (error) { } catch (error) {
res.status(500).json({ message: error.message }); console.error(error);
res.status(500).json({ error: 'Internal server error' });
} }
} };
export const updateUserProgress = async (req, res) => { // Get user's curriculum subscriptions and progress
export const getUserProgress = async (req, res) => {
const userId = req.params.userId; const userId = req.params.userId;
const { curriculumId, tutorialId, completed, marks } = req.body;
try { try {
let userProgress = await UserProgress.findOne({ userId }); const userProgress = await UserProgress.findOne({ userId });
if (!userProgress) { if (!userProgress) {
userProgress = new UserProgress({ userId }); return res.status(404).json({ message: 'User progress not found' });
}
res.status(200).json({ userProgress });
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Internal server error' });
} }
};
const curriculumProgress = userProgress.curriculumId.find(prog => prog.curriculumId.equals(curriculumId)); // Update task item progress and calculate overall progress
export const updateTaskItemProgress = async (req, res) => {
const { userId, curriculumCode, tutorialCode, taskItemTitle, taskItemMarkUser, taskItemSpentTime } = req.body;
if (!curriculumProgress) { try {
userProgress.curriculumId.push({ curriculumId }); const userProgress = await UserProgress.findOne({ userId });
if (!userProgress) {
return res.status(404).json({ message: 'User progress not found' });
} }
const tutorialProgress = curriculumProgress.tutorialProgress.find(prog => prog.tutorialId.equals(tutorialId)); // Find the curriculum, tutorial, and task item to update
const curriculumIndex = userProgress.curriculums.findIndex(c => c.curriculumCode === curriculumCode);
if (curriculumIndex === -1) {
return res.status(404).json({ message: 'Curriculum not found' });
}
if (!tutorialProgress) { const tutorialIndex = userProgress.curriculums[curriculumIndex].tutorials.findIndex(t => t.tutorialCode === tutorialCode);
curriculumProgress.tutorialProgress.push({ tutorialId, completed }); if (tutorialIndex === -1) {
} else { return res.status(404).json({ message: 'Tutorial not found' });
tutorialProgress.completed = completed; }
const taskItemIndex = userProgress.curriculums[curriculumIndex].tutorials[tutorialIndex].taskItems.findIndex(item => item.title === taskItemTitle);
if (taskItemIndex === -1) {
return res.status(404).json({ message: 'Task item not found' });
} }
userProgress.marks = marks; // Update task item progress
const taskItem = userProgress.curriculums[curriculumIndex].tutorials[tutorialIndex].taskItems[taskItemIndex];
taskItem.taskItemMarkUser = typeof taskItemMarkUser === 'string' ? parseFloat(taskItemMarkUser) : taskItemMarkUser;
taskItem.taskItemSpentTime = taskItemSpentTime;
// Calculate total task marks and spent time for the tutorial
const tutorial = userProgress.curriculums[curriculumIndex].tutorials[tutorialIndex];
tutorial.tutorialMarkUser = tutorial.taskItems.reduce((total, item) => total + item.taskItemMarkUser, 0);
tutorial.tutorialSpentTime = tutorial.taskItems.reduce((total, item) => total + item.taskItemSpentTime, 0);
// Calculate total tutorial marks and spent time for the curriculum
const curriculum = userProgress.curriculums[curriculumIndex];
curriculum.curriculumMarkUser = curriculum.tutorials.reduce((total, t) => total + t.tutorialMarkUser, 0);
curriculum.curriculumSpentTime = curriculum.tutorials.reduce((total, t) => total + t.tutorialSpentTime, 0);
// Calculate total curriculum marks and spent time for the user
userProgress.totalCurriculumsMarks = userProgress.curriculums.reduce((total, c) => total + c.curriculumMarkUser, 0);
userProgress.totalCurriculumSpentTime = userProgress.curriculums.reduce((total, c) => total + c.curriculumSpentTime, 0);
// Save the updated user progress
await userProgress.save(); await userProgress.save();
res.status(200).json(userProgress);
res.status(200).json({ message: 'Task item progress updated successfully' });
} catch (error) { } catch (error) {
res.status(500).json({ message: error.message }); console.error(error);
res.status(500).json({ error: 'Internal server error' });
} }
} };
...@@ -18,10 +18,14 @@ const curriculumSchema = new mongoose.Schema({ ...@@ -18,10 +18,14 @@ const curriculumSchema = new mongoose.Schema({
type: String, type: String,
unique: true, // Ensures unique values for curriculumCode unique: true, // Ensures unique values for curriculumCode
}, },
curriculumLevel: String, curriculumLevel: Number,
curriculumTitle: String, curriculumTitle: String,
curriculumDescription: String, curriculumDescription: String,
curriculumImage: String, curriculumImage: String,
curriculumMark: {
type: Number,
default: 0
},
tutorials: [{ tutorials: [{
type: mongoose.Schema.Types.ObjectId, type: mongoose.Schema.Types.ObjectId,
ref: "Tutorial", ref: "Tutorial",
...@@ -31,7 +35,11 @@ const curriculumSchema = new mongoose.Schema({ ...@@ -31,7 +35,11 @@ const curriculumSchema = new mongoose.Schema({
type: Number, type: Number,
default: 1, // Default status as active (1) default: 1, // Default status as active (1)
}, },
...commonFields ...commonFields,
subscribedUser: [{
type: mongoose.Schema.Types.ObjectId,
ref: "User", // Reference to the User model if you have one
}],
}); });
const Curriculum = mongoose.model("Curriculum", curriculumSchema); const Curriculum = mongoose.model("Curriculum", curriculumSchema);
......
...@@ -16,9 +16,13 @@ const commonFields = { ...@@ -16,9 +16,13 @@ const commonFields = {
const taskItemSchema = new mongoose.Schema({ const taskItemSchema = new mongoose.Schema({
title: String, title: String,
description: String, description: String,
howToDo: String, howToDo: [String],
referenceImage: String, referenceImage: String,
referenceVideo: String, referenceVideo: String,
taskItemMark : {
type: Number,
default: 0
}
// Additional fields for task items // Additional fields for task items
}); });
...@@ -30,6 +34,10 @@ const tutorialSchema = new mongoose.Schema({ ...@@ -30,6 +34,10 @@ const tutorialSchema = new mongoose.Schema({
tutorialTitle: String, tutorialTitle: String,
tutorialDescription: String, tutorialDescription: String,
tutorialImage: String, tutorialImage: String,
tutorialMarks: {
type: Number,
default: 0
},
taskItems: [taskItemSchema], // Embed task items as subdocuments taskItems: [taskItemSchema], // Embed task items as subdocuments
// Additional fields for tutorial details // Additional fields for tutorial details
status: { status: {
......
import mongoose from "mongoose"; import mongoose from "mongoose";
const userProgressSchema = new mongoose.Schema({ const taskItemSchema = new mongoose.Schema({
userId: { title: {
type: mongoose.Schema.Types.ObjectId, type: String,
required: true, required: true,
ref: 'User' // Reference to the User model
}, },
curriculumId: { description: {
type: mongoose.Schema.Types.ObjectId, type: String,
required: true, required: true,
ref: 'Curriculum' // Reference to the Curriculum model
}, },
tutorialProgress: [ howToDo: [String],
{ referenceImage: String,
tutorialId: { referenceVideo: String,
taskItemMark: {
type: Number,
default: 0
},
taskItemMarkUser: {
type: Number,
default: 0
},
taskItemSpentTime: {
type: Number,
default: 0
},
}, { _id: false });
const tutorialTypeUserProgressSchema = new mongoose.Schema({
tutorialCode: String,
tutorialTitle: String,
tutorialDescription: String,
tutorialImage: String,
tutorialMarks: {
type: Number,
default: 0
},
tutorialMarkUser: {
type: Number,
default: 0
},
tutorialSpentTime: {
type: Number,
default: 0
},
taskItems: [taskItemSchema],
}, { _id: false });
const curriculumTypeUserProgressSchema = new mongoose.Schema({
curriculumCode: String,
curriculumLevel: Number,
curriculumTitle: String,
curriculumDescription: String,
curriculumImage: String,
curriculumMark: {
type: Number,
default: 0
},
curriculumMarkUser: {
type: Number,
default: 0
},
curriculumSpentTime: {
type: Number,
default: 0
},
tutorials: [tutorialTypeUserProgressSchema],
}, { _id: false });
const userProgressSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId, type: mongoose.Schema.Types.ObjectId,
ref: 'Tutorial' // Reference to the Tutorial model required: true,
ref: 'User'
},
curriculums: [curriculumTypeUserProgressSchema],
totalCurriculumsMarks: {
type: Number,
default: 0
}, },
completed: { totalCurriculumSpentTime: {
type: Boolean,
default: false
}
}
],
marks: {
type: Number, type: Number,
default: 0 default: 0
} },
status: {
type: Number,
default: 1,
},
createdBy: String,
createdAt: {
type: Date,
default: new Date(),
},
updatedBy: String,
updatedAt: {
type: Date,
default: new Date(),
},
}); });
const UserProgress = mongoose.model("UserProgress", userProgressSchema); const UserProgress = mongoose.model("UserProgress", userProgressSchema);
......
import express from "express"; import express from "express";
import { deleteUser, getUser, getUserAccordingToType, getUsers, signIn, signUp, updateUser } from "../controllers/user.controller.js"; import { currentUser, deleteUser, getUser, getUserAccordingToType, getUsers, signIn, signUp, updateUser } from "../controllers/user.controller.js";
import auth from "../middleware/auth.middleware.js";
const router = express.Router(); const router = express.Router();
router.post('/sign-in', signIn) router.post('/sign-in', signIn)
router.post('/sign-up', signUp) router.post('/sign-up', signUp)
router.get('/all', getUsers); router.get('/all', getUsers);
router.get('/current-user', auth, currentUser);
router.get('/:id', getUser); router.get('/:id', getUser);
router.get('/all/type/:userType', getUserAccordingToType); router.get('/all/type/:userType', getUserAccordingToType);
router.put('/:id', updateUser); router.put('/:id', updateUser);
......
import express from "express"; import express from "express";
import { getUserProgress, updateUserProgress } from "../controllers/userProgress.controller.js"; import { getUserProgress, subscribeCurriculum, updateTaskItemProgress } from "../controllers/userProgress.controller.js";
const router = express.Router(); const router = express.Router();
router.post('/subscribe-curriculum', subscribeCurriculum);
router.get('/:userId', getUserProgress); router.get('/:userId', getUserProgress);
router.post('/:userId', updateUserProgress); router.put('/update-task-item-progress', updateTaskItemProgress);
export default router; export default router;
...@@ -23,9 +23,13 @@ import userProgressRoutes from "./routes/userProgress.routes.js"; ...@@ -23,9 +23,13 @@ import userProgressRoutes from "./routes/userProgress.routes.js";
dotenv.config(); dotenv.config();
const app = express(); const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
};
app.use(bodyParser.json({ limit: "30mb", extended: true })); app.use(bodyParser.json({ limit: "30mb", extended: true }));
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(cors()); app.use(cors(corsOptions));
//end //end
app.get("/", (req, res) => { app.get("/", (req, res) => {
......
...@@ -2,1062 +2,1100 @@ ...@@ -2,1062 +2,1100 @@
# yarn lockfile v1 # yarn lockfile v1
"@mongodb-js/saslprep@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz#022fa36620a7287d17acd05c4aae1e5f390d250d"
integrity sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==
dependencies:
sparse-bitfield "^3.0.3"
"@types/node@*": "@types/node@*":
version "20.5.7" "integrity" "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g=="
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.7.tgz#4b8ecac87fbefbc92f431d09c30e176fc0a7c377" "resolved" "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz"
integrity sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA== "version" "20.1.2"
"@types/webidl-conversions@*": "@types/webidl-conversions@*":
version "7.0.0" "integrity" "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog=="
resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" "resolved" "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz"
integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog== "version" "7.0.0"
"@types/whatwg-url@^8.2.1": "@types/whatwg-url@^8.2.1":
version "8.2.2" "integrity" "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA=="
resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" "resolved" "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz"
integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== "version" "8.2.2"
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/webidl-conversions" "*" "@types/webidl-conversions" "*"
abbrev@1: "abbrev@1":
version "1.1.1" "integrity" "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" "resolved" "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== "version" "1.1.1"
accepts@~1.3.8: "accepts@~1.3.8":
version "1.3.8" "integrity" "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" "resolved" "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz"
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== "version" "1.3.8"
dependencies: dependencies:
mime-types "~2.1.34" "mime-types" "~2.1.34"
negotiator "0.6.3" "negotiator" "0.6.3"
ansi-regex@^2.0.0: "ansi-regex@^2.0.0":
version "2.1.1" "integrity" "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== "version" "2.1.1"
ansi-styles@^2.2.1: "ansi-styles@^2.2.1":
version "2.2.1" "integrity" "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== "version" "2.2.1"
anymatch@~3.1.2: "anymatch@~3.1.2":
version "3.1.3" "integrity" "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== "version" "3.1.3"
dependencies: dependencies:
normalize-path "^3.0.0" "normalize-path" "^3.0.0"
picomatch "^2.0.4" "picomatch" "^2.0.4"
append-field@^1.0.0: "append-field@^1.0.0":
version "1.0.0" "integrity" "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" "resolved" "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz"
integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== "version" "1.0.0"
array-flatten@1.1.1: "array-flatten@1.1.1":
version "1.1.1" "integrity" "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" "resolved" "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== "version" "1.1.1"
balanced-match@^1.0.0: "balanced-match@^1.0.0":
version "1.0.2" "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== "version" "1.0.2"
bcryptjs@^2.4.3: "bcryptjs@^2.4.3":
version "2.4.3" "integrity" "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" "resolved" "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz"
integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== "version" "2.4.3"
binary-extensions@^2.0.0: "binary-extensions@^2.0.0":
version "2.2.0" "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== "version" "2.2.0"
body-parser@1.20.1: "body-parser@^1.20.2":
version "1.20.1" "integrity" "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA=="
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" "resolved" "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz"
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== "version" "1.20.2"
dependencies: dependencies:
bytes "3.1.2" "bytes" "3.1.2"
content-type "~1.0.4" "content-type" "~1.0.5"
debug "2.6.9" "debug" "2.6.9"
depd "2.0.0" "depd" "2.0.0"
destroy "1.2.0" "destroy" "1.2.0"
http-errors "2.0.0" "http-errors" "2.0.0"
iconv-lite "0.4.24" "iconv-lite" "0.4.24"
on-finished "2.4.1" "on-finished" "2.4.1"
qs "6.11.0" "qs" "6.11.0"
raw-body "2.5.1" "raw-body" "2.5.2"
type-is "~1.6.18" "type-is" "~1.6.18"
unpipe "1.0.0" "unpipe" "1.0.0"
body-parser@^1.20.2: "body-parser@1.20.1":
version "1.20.2" "integrity" "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw=="
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" "resolved" "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== "version" "1.20.1"
dependencies: dependencies:
bytes "3.1.2" "bytes" "3.1.2"
content-type "~1.0.5" "content-type" "~1.0.4"
debug "2.6.9" "debug" "2.6.9"
depd "2.0.0" "depd" "2.0.0"
destroy "1.2.0" "destroy" "1.2.0"
http-errors "2.0.0" "http-errors" "2.0.0"
iconv-lite "0.4.24" "iconv-lite" "0.4.24"
on-finished "2.4.1" "on-finished" "2.4.1"
qs "6.11.0" "qs" "6.11.0"
raw-body "2.5.2" "raw-body" "2.5.1"
type-is "~1.6.18" "type-is" "~1.6.18"
unpipe "1.0.0" "unpipe" "1.0.0"
brace-expansion@^1.1.7: "brace-expansion@^1.1.7":
version "1.1.11" "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== "version" "1.1.11"
dependencies: dependencies:
balanced-match "^1.0.0" "balanced-match" "^1.0.0"
concat-map "0.0.1" "concat-map" "0.0.1"
braces@~3.0.2: "braces@~3.0.2":
version "3.0.2" "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== "version" "3.0.2"
dependencies: dependencies:
fill-range "^7.0.1" "fill-range" "^7.0.1"
bson@^5.4.0: "bson@^5.2.0":
version "5.4.0" "integrity" "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag=="
resolved "https://registry.yarnpkg.com/bson/-/bson-5.4.0.tgz#0eea77276d490953ad8616b483298dbff07384c6" "resolved" "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz"
integrity sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA== "version" "5.3.0"
buffer-equal-constant-time@1.0.1: "buffer-equal-constant-time@1.0.1":
version "1.0.1" "integrity" "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" "resolved" "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== "version" "1.0.1"
buffer-from@^1.0.0: "buffer-from@^1.0.0":
version "1.1.2" "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== "version" "1.1.2"
busboy@^1.0.0: "busboy@^1.0.0":
version "1.6.0" "integrity" "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" "resolved" "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz"
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== "version" "1.6.0"
dependencies: dependencies:
streamsearch "^1.1.0" "streamsearch" "^1.1.0"
bytes@3.1.2: "bytes@3.1.2":
version "3.1.2" "integrity" "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== "version" "3.1.2"
call-bind@^1.0.0: "call-bind@^1.0.0":
version "1.0.2" "integrity" "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== "version" "1.0.2"
dependencies: dependencies:
function-bind "^1.1.1" "function-bind" "^1.1.1"
get-intrinsic "^1.0.2" "get-intrinsic" "^1.0.2"
chalk@^1.1.3: "chalk@^1.1.3":
version "1.1.3" "integrity" "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A=="
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" "resolved" "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== "version" "1.1.3"
dependencies: dependencies:
ansi-styles "^2.2.1" "ansi-styles" "^2.2.1"
escape-string-regexp "^1.0.2" "escape-string-regexp" "^1.0.2"
has-ansi "^2.0.0" "has-ansi" "^2.0.0"
strip-ansi "^3.0.0" "strip-ansi" "^3.0.0"
supports-color "^2.0.0" "supports-color" "^2.0.0"
chokidar@^3.5.2: "chokidar@^3.5.2":
version "3.5.3" "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== "version" "3.5.3"
dependencies: dependencies:
anymatch "~3.1.2" "anymatch" "~3.1.2"
braces "~3.0.2" "braces" "~3.0.2"
glob-parent "~5.1.2" "glob-parent" "~5.1.2"
is-binary-path "~2.1.0" "is-binary-path" "~2.1.0"
is-glob "~4.0.1" "is-glob" "~4.0.1"
normalize-path "~3.0.0" "normalize-path" "~3.0.0"
readdirp "~3.6.0" "readdirp" "~3.6.0"
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" "fsevents" "~2.3.2"
concat-map@0.0.1: "concat-map@0.0.1":
version "0.0.1" "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== "version" "0.0.1"
concat-stream@^1.5.2: "concat-stream@^1.5.2":
version "1.6.2" "integrity" "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" "resolved" "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== "version" "1.6.2"
dependencies: dependencies:
buffer-from "^1.0.0" "buffer-from" "^1.0.0"
inherits "^2.0.3" "inherits" "^2.0.3"
readable-stream "^2.2.2" "readable-stream" "^2.2.2"
typedarray "^0.0.6" "typedarray" "^0.0.6"
content-disposition@0.5.4: "content-disposition@0.5.4":
version "0.5.4" "integrity" "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" "resolved" "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== "version" "0.5.4"
dependencies: dependencies:
safe-buffer "5.2.1" "safe-buffer" "5.2.1"
content-type@~1.0.4, content-type@~1.0.5: "content-type@~1.0.4", "content-type@~1.0.5":
version "1.0.5" "integrity" "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" "resolved" "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== "version" "1.0.5"
cookie-signature@1.0.6: "cookie-signature@1.0.6":
version "1.0.6" "integrity" "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== "version" "1.0.6"
cookie@0.5.0: "cookie@0.5.0":
version "0.5.0" "integrity" "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== "version" "0.5.0"
core-util-is@~1.0.0: "core-util-is@~1.0.0":
version "1.0.3" "integrity" "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" "resolved" "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== "version" "1.0.3"
cors@^2.8.5: "cors@^2.8.5":
version "2.8.5" "integrity" "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" "resolved" "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== "version" "2.8.5"
dependencies: dependencies:
object-assign "^4" "object-assign" "^4"
vary "^1" "vary" "^1"
debug@2.6.9: "debug@^3.2.7":
version "2.6.9" "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== "version" "3.2.7"
dependencies: dependencies:
ms "2.0.0" "ms" "^2.1.1"
debug@4.x: "debug@2.6.9":
version "4.3.4" "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== "version" "2.6.9"
dependencies: dependencies:
ms "2.1.2" "ms" "2.0.0"
debug@^3.2.7: "debug@4.x":
version "3.2.7" "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== "version" "4.3.4"
dependencies: dependencies:
ms "^2.1.1" "ms" "2.1.2"
depd@2.0.0: "depd@2.0.0":
version "2.0.0" "integrity" "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" "resolved" "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== "version" "2.0.0"
destroy@1.2.0: "destroy@1.2.0":
version "1.2.0" "integrity" "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== "version" "1.2.0"
dotenv@^16.0.3: "dotenv@^16.0.3":
version "16.3.1" "integrity" "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" "resolved" "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz"
integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== "version" "16.0.3"
ecdsa-sig-formatter@1.0.11: "ecdsa-sig-formatter@1.0.11":
version "1.0.11" "integrity" "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" "resolved" "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== "version" "1.0.11"
dependencies: dependencies:
safe-buffer "^5.0.1" "safe-buffer" "^5.0.1"
ee-first@1.1.1: "ee-first@1.1.1":
version "1.1.1" "integrity" "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== "version" "1.1.1"
encodeurl@~1.0.2: "encodeurl@~1.0.2":
version "1.0.2" "integrity" "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== "version" "1.0.2"
escape-html@~1.0.3: "escape-html@~1.0.3":
version "1.0.3" "integrity" "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" "resolved" "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== "version" "1.0.3"
escape-string-regexp@^1.0.2: "escape-string-regexp@^1.0.2":
version "1.0.5" "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== "version" "1.0.5"
etag@~1.8.1: "etag@~1.8.1":
version "1.8.1" "integrity" "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== "version" "1.8.1"
express@^4.18.2: "express@^4.18.2":
version "4.18.2" "integrity" "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ=="
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" "resolved" "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== "version" "4.18.2"
dependencies: dependencies:
accepts "~1.3.8" "accepts" "~1.3.8"
array-flatten "1.1.1" "array-flatten" "1.1.1"
body-parser "1.20.1" "body-parser" "1.20.1"
content-disposition "0.5.4" "content-disposition" "0.5.4"
content-type "~1.0.4" "content-type" "~1.0.4"
cookie "0.5.0" "cookie" "0.5.0"
cookie-signature "1.0.6" "cookie-signature" "1.0.6"
debug "2.6.9" "debug" "2.6.9"
depd "2.0.0" "depd" "2.0.0"
encodeurl "~1.0.2" "encodeurl" "~1.0.2"
escape-html "~1.0.3" "escape-html" "~1.0.3"
etag "~1.8.1" "etag" "~1.8.1"
finalhandler "1.2.0" "finalhandler" "1.2.0"
fresh "0.5.2" "fresh" "0.5.2"
http-errors "2.0.0" "http-errors" "2.0.0"
merge-descriptors "1.0.1" "merge-descriptors" "1.0.1"
methods "~1.1.2" "methods" "~1.1.2"
on-finished "2.4.1" "on-finished" "2.4.1"
parseurl "~1.3.3" "parseurl" "~1.3.3"
path-to-regexp "0.1.7" "path-to-regexp" "0.1.7"
proxy-addr "~2.0.7" "proxy-addr" "~2.0.7"
qs "6.11.0" "qs" "6.11.0"
range-parser "~1.2.1" "range-parser" "~1.2.1"
safe-buffer "5.2.1" "safe-buffer" "5.2.1"
send "0.18.0" "send" "0.18.0"
serve-static "1.15.0" "serve-static" "1.15.0"
setprototypeof "1.2.0" "setprototypeof" "1.2.0"
statuses "2.0.1" "statuses" "2.0.1"
type-is "~1.6.18" "type-is" "~1.6.18"
utils-merge "1.0.1" "utils-merge" "1.0.1"
vary "~1.1.2" "vary" "~1.1.2"
fill-range@^7.0.1: "fill-range@^7.0.1":
version "7.0.1" "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== "version" "7.0.1"
dependencies: dependencies:
to-regex-range "^5.0.1" "to-regex-range" "^5.0.1"
finalhandler@1.2.0: "finalhandler@1.2.0":
version "1.2.0" "integrity" "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg=="
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz"
integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== "version" "1.2.0"
dependencies: dependencies:
debug "2.6.9" "debug" "2.6.9"
encodeurl "~1.0.2" "encodeurl" "~1.0.2"
escape-html "~1.0.3" "escape-html" "~1.0.3"
on-finished "2.4.1" "on-finished" "2.4.1"
parseurl "~1.3.3" "parseurl" "~1.3.3"
statuses "2.0.1" "statuses" "2.0.1"
unpipe "~1.0.0" "unpipe" "~1.0.0"
forwarded@0.2.0: "forwarded@0.2.0":
version "0.2.0" "integrity" "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" "resolved" "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== "version" "0.2.0"
fresh@0.5.2: "fresh@0.5.2":
version "0.5.2" "integrity" "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" "resolved" "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== "version" "0.5.2"
fsevents@~2.3.2: "function-bind@^1.1.1":
version "2.3.3" "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== "version" "1.1.1"
function-bind@^1.1.1: "get-intrinsic@^1.0.2":
version "1.1.1" "integrity" "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q=="
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== "version" "1.2.0"
dependencies:
get-intrinsic@^1.0.2: "function-bind" "^1.1.1"
version "1.2.1" "has" "^1.0.3"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" "has-symbols" "^1.0.3"
integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
dependencies: "glob-parent@~5.1.2":
function-bind "^1.1.1" "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="
has "^1.0.3" "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
has-proto "^1.0.1" "version" "5.1.2"
has-symbols "^1.0.3" dependencies:
"is-glob" "^4.0.1"
glob-parent@~5.1.2:
version "5.1.2" "has-ansi@^2.0.0":
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" "integrity" "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg=="
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== "resolved" "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
dependencies: "version" "2.0.0"
is-glob "^4.0.1" dependencies:
"ansi-regex" "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0" "has-flag@^3.0.0":
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
dependencies: "version" "3.0.0"
ansi-regex "^2.0.0"
"has-symbols@^1.0.3":
has-flag@^3.0.0: "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
version "3.0.0" "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" "version" "1.0.3"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
"has@^1.0.3":
has-proto@^1.0.1: "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="
version "1.0.1" "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" "version" "1.0.3"
integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== dependencies:
"function-bind" "^1.1.1"
has-symbols@^1.0.3:
version "1.0.3" "http-errors@2.0.0":
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" "integrity" "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"
"version" "2.0.0"
has@^1.0.3: dependencies:
version "1.0.3" "depd" "2.0.0"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" "inherits" "2.0.4"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== "setprototypeof" "1.2.0"
dependencies: "statuses" "2.0.1"
function-bind "^1.1.1" "toidentifier" "1.0.1"
http-errors@2.0.0: "iconv-lite@0.4.24":
version "2.0.0" "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== "version" "0.4.24"
dependencies: dependencies:
depd "2.0.0" "safer-buffer" ">= 2.1.2 < 3"
inherits "2.0.4"
setprototypeof "1.2.0" "ignore-by-default@^1.0.1":
statuses "2.0.1" "integrity" "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
toidentifier "1.0.1" "resolved" "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
"version" "1.0.1"
iconv-lite@0.4.24:
version "0.4.24" "inherits@^2.0.3", "inherits@~2.0.3", "inherits@2.0.4":
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
dependencies: "version" "2.0.4"
safer-buffer ">= 2.1.2 < 3"
"ip@^2.0.0":
ignore-by-default@^1.0.1: "integrity" "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ=="
version "1.0.1" "resolved" "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" "version" "2.0.0"
integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
"ipaddr.js@1.9.1":
inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: "integrity" "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
version "2.0.4" "resolved" "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" "version" "1.9.1"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
"is-binary-path@~2.1.0":
ip@^2.0.0: "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="
version "2.0.0" "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" "version" "2.1.0"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== dependencies:
"binary-extensions" "^2.0.0"
ipaddr.js@1.9.1:
version "1.9.1" "is-extglob@^2.1.1":
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" "integrity" "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
"version" "2.1.1"
is-binary-path@~2.1.0:
version "2.1.0" "is-glob@^4.0.1", "is-glob@~4.0.1":
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
dependencies: "version" "4.0.3"
binary-extensions "^2.0.0" dependencies:
"is-extglob" "^2.1.1"
is-extglob@^2.1.1:
version "2.1.1" "is-number@^7.0.0":
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
"version" "7.0.0"
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.3" "isarray@~1.0.0":
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" "integrity" "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== "resolved" "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
dependencies: "version" "1.0.0"
is-extglob "^2.1.1"
"js-tokens@^3.0.0 || ^4.0.0":
is-number@^7.0.0: "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
version "7.0.0" "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" "version" "4.0.0"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
"jsonwebtoken@^9.0.0":
isarray@~1.0.0: "integrity" "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw=="
version "1.0.0" "resolved" "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" "version" "9.0.0"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== dependencies:
"jws" "^3.2.2"
jsonwebtoken@^9.0.0: "lodash" "^4.17.21"
version "9.0.1" "ms" "^2.1.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz#81d8c901c112c24e497a55daf6b2be1225b40145" "semver" "^7.3.8"
integrity sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==
dependencies: "jwa@^1.4.1":
jws "^3.2.2" "integrity" "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA=="
lodash "^4.17.21" "resolved" "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz"
ms "^2.1.1" "version" "1.4.1"
semver "^7.3.8" dependencies:
"buffer-equal-constant-time" "1.0.1"
jwa@^1.4.1: "ecdsa-sig-formatter" "1.0.11"
version "1.4.1" "safe-buffer" "^5.0.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== "jws@^3.2.2":
dependencies: "integrity" "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="
buffer-equal-constant-time "1.0.1" "resolved" "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz"
ecdsa-sig-formatter "1.0.11" "version" "3.2.2"
safe-buffer "^5.0.1" dependencies:
"jwa" "^1.4.1"
jws@^3.2.2: "safe-buffer" "^5.0.1"
version "3.2.2"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" "kareem@2.5.1":
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== "integrity" "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA=="
dependencies: "resolved" "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz"
jwa "^1.4.1" "version" "2.5.1"
safe-buffer "^5.0.1"
"lodash@^4.17.21":
kareem@2.5.1: "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
version "2.5.1" "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.5.1.tgz#7b8203e11819a8e77a34b3517d3ead206764d15d" "version" "4.17.21"
integrity sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==
"loose-envify@^1.1.0", "loose-envify@^1.4.0":
lodash@^4.17.21: "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="
version "4.17.21" "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" "version" "1.4.0"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== dependencies:
"js-tokens" "^3.0.0 || ^4.0.0"
lru-cache@^6.0.0:
version "6.0.0" "lru-cache@^6.0.0":
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
dependencies: "version" "6.0.0"
yallist "^4.0.0" dependencies:
"yallist" "^4.0.0"
media-typer@0.3.0:
version "0.3.0" "media-typer@0.3.0":
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" "integrity" "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== "resolved" "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
"version" "0.3.0"
memory-pager@^1.0.2:
version "1.5.0" "memory-pager@^1.0.2":
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" "integrity" "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== "resolved" "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz"
"version" "1.5.0"
merge-descriptors@1.0.1:
version "1.0.1" "merge-descriptors@1.0.1":
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" "integrity" "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== "resolved" "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
"version" "1.0.1"
methods@~1.1.2:
version "1.1.2" "methods@~1.1.2":
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" "integrity" "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== "resolved" "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
"version" "1.1.2"
mime-db@1.52.0:
version "1.52.0" "mime-db@1.52.0":
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
"version" "1.52.0"
mime-types@~2.1.24, mime-types@~2.1.34:
version "2.1.35" "mime-types@~2.1.24", "mime-types@~2.1.34":
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
dependencies: "version" "2.1.35"
mime-db "1.52.0" dependencies:
"mime-db" "1.52.0"
mime@1.6.0:
version "1.6.0" "mime@1.6.0":
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== "resolved" "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
"version" "1.6.0"
minimatch@^3.1.2:
version "3.1.2" "minimatch@^3.1.2":
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
dependencies: "version" "3.1.2"
brace-expansion "^1.1.7" dependencies:
"brace-expansion" "^1.1.7"
minimist@^1.2.6:
version "1.2.8" "minimist@^1.2.6":
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" "integrity" "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
"version" "1.2.8"
mkdirp@^0.5.4:
version "0.5.6" "mkdirp@^0.5.4":
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" "integrity" "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz"
dependencies: "version" "0.5.6"
minimist "^1.2.6" dependencies:
"minimist" "^1.2.6"
mongodb-connection-string-url@^2.6.0:
version "2.6.0" "mongodb-connection-string-url@^2.6.0":
resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" "integrity" "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ=="
integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ== "resolved" "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz"
"version" "2.6.0"
dependencies: dependencies:
"@types/whatwg-url" "^8.2.1" "@types/whatwg-url" "^8.2.1"
whatwg-url "^11.0.0" "whatwg-url" "^11.0.0"
mongodb@5.8.1: "mongodb@5.3.0":
version "5.8.1" "integrity" "sha512-Wy/sbahguL8c3TXQWXmuBabiLD+iVmz+tOgQf+FwkCjhUIorqbAxRbbz00g4ZoN4sXIPwpAlTANMaGRjGGTikQ=="
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-5.8.1.tgz#dc201adfbd6c6d73401cdcf12ebdb75f14771faf" "resolved" "https://registry.npmjs.org/mongodb/-/mongodb-5.3.0.tgz"
integrity sha512-wKyh4kZvm6NrCPH8AxyzXm3JBoEf4Xulo0aUWh3hCgwgYJxyQ1KLST86ZZaSWdj6/kxYUA3+YZuyADCE61CMSg== "version" "5.3.0"
dependencies: dependencies:
bson "^5.4.0" "bson" "^5.2.0"
mongodb-connection-string-url "^2.6.0" "mongodb-connection-string-url" "^2.6.0"
socks "^2.7.1" "socks" "^2.7.1"
optionalDependencies: optionalDependencies:
"@mongodb-js/saslprep" "^1.1.0" "saslprep" "^1.0.3"
mongoose@^7.1.1: "mongoose@^7.1.1":
version "7.5.0" "integrity" "sha512-AIxaWwGY+td7QOMk4NgK6fbRuGovFyDzv65nU1uj1DsUh3lpjfP3iFYHSR+sUKrs7nbp19ksLlRXkmInBteSCA=="
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-7.5.0.tgz#d10003ffc1ff876d761c7cbca6844ddd2aadd42f" "resolved" "https://registry.npmjs.org/mongoose/-/mongoose-7.1.1.tgz"
integrity sha512-FpOWOb0AJuaVcplmEyIJ2eCbVGe4gOoniPD+pmft5BrGrNrsFcnYXlERdXtBApGHMHPwD7WbxTyhCbUNr72F3Q== "version" "7.1.1"
dependencies: dependencies:
bson "^5.4.0" "bson" "^5.2.0"
kareem "2.5.1" "kareem" "2.5.1"
mongodb "5.8.1" "mongodb" "5.3.0"
mpath "0.9.0" "mpath" "0.9.0"
mquery "5.0.0" "mquery" "5.0.0"
ms "2.1.3" "ms" "2.1.3"
sift "16.0.1" "sift" "16.0.1"
mpath@0.9.0: "mpath@0.9.0":
version "0.9.0" "integrity" "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" "resolved" "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz"
integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== "version" "0.9.0"
mquery@5.0.0: "mquery@5.0.0":
version "5.0.0" "integrity" "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg=="
resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" "resolved" "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz"
integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== "version" "5.0.0"
dependencies: dependencies:
debug "4.x" "debug" "4.x"
ms@2.0.0: "ms@^2.1.1":
version "2.0.0" "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== "version" "2.1.3"
ms@2.1.2: "ms@2.0.0":
version "2.1.2" "integrity" "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== "version" "2.0.0"
ms@2.1.3, ms@^2.1.1: "ms@2.1.2":
version "2.1.3" "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== "version" "2.1.2"
multer@^1.4.5-lts.1: "ms@2.1.3":
version "1.4.5-lts.1" "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.5-lts.1.tgz#803e24ad1984f58edffbc79f56e305aec5cfd1ac" "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ== "version" "2.1.3"
dependencies:
append-field "^1.0.0" "multer@^1.4.5-lts.1":
busboy "^1.0.0" "integrity" "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ=="
concat-stream "^1.5.2" "resolved" "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz"
mkdirp "^0.5.4" "version" "1.4.5-lts.1"
object-assign "^4.1.1" dependencies:
type-is "^1.6.4" "append-field" "^1.0.0"
xtend "^4.0.0" "busboy" "^1.0.0"
"concat-stream" "^1.5.2"
negotiator@0.6.3: "mkdirp" "^0.5.4"
version "0.6.3" "object-assign" "^4.1.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" "type-is" "^1.6.4"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== "xtend" "^4.0.0"
nodemailer@^6.9.1: "negotiator@0.6.3":
version "6.9.4" "integrity" "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.4.tgz#93bd4a60eb0be6fa088a0483340551ebabfd2abf" "resolved" "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
integrity sha512-CXjQvrQZV4+6X5wP6ZIgdehJamI63MFoYFGGPtHudWym9qaEHDNdPzaj5bfMCvxG1vhAileSWW90q7nL0N36mA== "version" "0.6.3"
nodemon@^2.0.22: "nodemailer@^6.9.1":
version "2.0.22" "integrity" "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA=="
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258" "resolved" "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz"
integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ== "version" "6.9.1"
dependencies:
chokidar "^3.5.2" "nodemon@^2.0.22":
debug "^3.2.7" "integrity" "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ=="
ignore-by-default "^1.0.1" "resolved" "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz"
minimatch "^3.1.2" "version" "2.0.22"
pstree.remy "^1.1.8" dependencies:
semver "^5.7.1" "chokidar" "^3.5.2"
simple-update-notifier "^1.0.7" "debug" "^3.2.7"
supports-color "^5.5.0" "ignore-by-default" "^1.0.1"
touch "^3.1.0" "minimatch" "^3.1.2"
undefsafe "^2.0.5" "pstree.remy" "^1.1.8"
"semver" "^5.7.1"
nopt@~1.0.10: "simple-update-notifier" "^1.0.7"
version "1.0.10" "supports-color" "^5.5.0"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" "touch" "^3.1.0"
integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== "undefsafe" "^2.0.5"
dependencies:
abbrev "1" "nopt@~1.0.10":
"integrity" "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg=="
normalize-path@^3.0.0, normalize-path@~3.0.0: "resolved" "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"
version "3.0.0" "version" "1.0.10"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" dependencies:
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== "abbrev" "1"
object-assign@^4, object-assign@^4.1.1: "normalize-path@^3.0.0", "normalize-path@~3.0.0":
version "4.1.1" "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== "version" "3.0.0"
object-inspect@^1.9.0: "object-assign@^4", "object-assign@^4.1.1":
version "1.12.3" "integrity" "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== "version" "4.1.1"
on-finished@2.4.1: "object-inspect@^1.9.0":
version "2.4.1" "integrity" "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== "version" "1.12.3"
dependencies:
ee-first "1.1.1" "on-finished@2.4.1":
"integrity" "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="
parseurl@~1.3.3: "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz"
version "1.3.3" "version" "2.4.1"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" dependencies:
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== "ee-first" "1.1.1"
path-to-regexp@0.1.7: "parseurl@~1.3.3":
version "0.1.7" "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" "resolved" "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== "version" "1.3.3"
picomatch@^2.0.4, picomatch@^2.2.1: "path-to-regexp@0.1.7":
version "2.3.1" "integrity" "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== "version" "0.1.7"
process-nextick-args@~2.0.0: "picomatch@^2.0.4", "picomatch@^2.2.1":
version "2.0.1" "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== "version" "2.3.1"
proxy-addr@~2.0.7: "process-nextick-args@~2.0.0":
version "2.0.7" "integrity" "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" "resolved" "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== "version" "2.0.1"
dependencies:
forwarded "0.2.0" "prop-types@^15.5.10", "prop-types@^15.6.0", "prop-types@^15.6.2":
ipaddr.js "1.9.1" "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="
"resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
pstree.remy@^1.1.8: "version" "15.8.1"
version "1.1.8" dependencies:
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" "loose-envify" "^1.4.0"
integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== "object-assign" "^4.1.1"
"react-is" "^16.13.1"
punycode@^2.1.1:
version "2.3.0" "proxy-addr@~2.0.7":
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" "integrity" "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== "resolved" "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
"version" "2.0.7"
qs@6.11.0: dependencies:
version "6.11.0" "forwarded" "0.2.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" "ipaddr.js" "1.9.1"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies: "pstree.remy@^1.1.8":
side-channel "^1.0.4" "integrity" "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
"resolved" "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz"
range-parser@~1.2.1: "version" "1.1.8"
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" "punycode@^2.1.1":
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== "integrity" "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
"resolved" "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
raw-body@2.5.1: "version" "2.3.0"
version "2.5.1"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" "qs@6.11.0":
integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== "integrity" "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q=="
dependencies: "resolved" "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz"
bytes "3.1.2" "version" "6.11.0"
http-errors "2.0.0" dependencies:
iconv-lite "0.4.24" "side-channel" "^1.0.4"
unpipe "1.0.0"
"range-parser@~1.2.1":
raw-body@2.5.2: "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
version "2.5.2" "resolved" "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" "version" "1.2.1"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies: "raw-body@2.5.1":
bytes "3.1.2" "integrity" "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig=="
http-errors "2.0.0" "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz"
iconv-lite "0.4.24" "version" "2.5.1"
unpipe "1.0.0" dependencies:
"bytes" "3.1.2"
readable-stream@^2.2.2: "http-errors" "2.0.0"
version "2.3.8" "iconv-lite" "0.4.24"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" "unpipe" "1.0.0"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies: "raw-body@2.5.2":
core-util-is "~1.0.0" "integrity" "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="
inherits "~2.0.3" "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz"
isarray "~1.0.0" "version" "2.5.2"
process-nextick-args "~2.0.0" dependencies:
safe-buffer "~5.1.1" "bytes" "3.1.2"
string_decoder "~1.1.1" "http-errors" "2.0.0"
util-deprecate "~1.0.1" "iconv-lite" "0.4.24"
"unpipe" "1.0.0"
readdirp@~3.6.0:
version "3.6.0" "react-ga@^2.2.0":
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" "integrity" "sha512-AjC7UOZMvygrWTc2hKxTDvlMXEtbmA0IgJjmkhgmQQ3RkXrWR11xEagLGFGaNyaPnmg24oaIiaNPnEoftUhfXA=="
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== "resolved" "https://registry.npmjs.org/react-ga/-/react-ga-2.7.0.tgz"
dependencies: "version" "2.7.0"
picomatch "^2.2.1"
"react-is@^16.13.1":
safe-buffer@5.2.1, safe-buffer@^5.0.1: "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
version "5.2.1" "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" "version" "16.13.1"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
"react-mic@^12.4.6":
safe-buffer@~5.1.0, safe-buffer@~5.1.1: "integrity" "sha512-2/DZoz7thR2nJyekF10zBvs/7a8HhUQ4L8MV6BpC+Q/T8G1MvpRHGSHjSlVtnbzaCMDJ3R1MdThoLu15WuVh/g=="
version "5.1.2" "resolved" "https://registry.npmjs.org/react-mic/-/react-mic-12.4.6.tgz"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" "version" "12.4.6"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== dependencies:
"prop-types" "^15.5.10"
"react-ga" "^2.2.0"
"react@^15.6.2 || ^16.0", "react@16.x":
"integrity" "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g=="
"resolved" "https://registry.npmjs.org/react/-/react-16.14.0.tgz"
"version" "16.14.0"
dependencies:
"core-util-is" "~1.0.0"
"inherits" "~2.0.3"
"isarray" "~1.0.0"
"process-nextick-args" "~2.0.0"
"safe-buffer" "~5.1.1"
"string_decoder" "~1.1.1"
"util-deprecate" "~1.0.1"
"readdirp@~3.6.0":
"integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="
"resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
"version" "3.6.0"
dependencies:
"picomatch" "^2.2.1"
"safe-buffer@^5.0.1", "safe-buffer@5.2.1":
"integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
"resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
"version" "5.2.1"
"safe-buffer@~5.1.0":
"integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
"resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
"version" "5.1.2"
"safe-buffer@~5.1.1":
"integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
"resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
"version" "5.1.2"
"safer-buffer@>= 2.1.2 < 3": "safer-buffer@>= 2.1.2 < 3":
version "2.1.2" "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== "version" "2.1.2"
semver@^5.7.1: "saslprep@^1.0.3":
version "5.7.2" "integrity" "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag=="
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" "resolved" "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== "version" "1.0.3"
dependencies:
semver@^7.3.8: "sparse-bitfield" "^3.0.3"
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" "semver@^5.7.1":
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
dependencies: "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
lru-cache "^6.0.0" "version" "5.7.1"
semver@~7.0.0: "semver@^7.3.8":
version "7.0.0" "integrity" "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA=="
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" "resolved" "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== "version" "7.5.0"
dependencies:
send@0.18.0: "lru-cache" "^6.0.0"
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" "semver@~7.0.0":
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== "integrity" "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
dependencies: "resolved" "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz"
debug "2.6.9" "version" "7.0.0"
depd "2.0.0"
destroy "1.2.0" "send@0.18.0":
encodeurl "~1.0.2" "integrity" "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg=="
escape-html "~1.0.3" "resolved" "https://registry.npmjs.org/send/-/send-0.18.0.tgz"
etag "~1.8.1" "version" "0.18.0"
fresh "0.5.2" dependencies:
http-errors "2.0.0" "debug" "2.6.9"
mime "1.6.0" "depd" "2.0.0"
ms "2.1.3" "destroy" "1.2.0"
on-finished "2.4.1" "encodeurl" "~1.0.2"
range-parser "~1.2.1" "escape-html" "~1.0.3"
statuses "2.0.1" "etag" "~1.8.1"
"fresh" "0.5.2"
serve-static@1.15.0: "http-errors" "2.0.0"
version "1.15.0" "mime" "1.6.0"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" "ms" "2.1.3"
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== "on-finished" "2.4.1"
dependencies: "range-parser" "~1.2.1"
encodeurl "~1.0.2" "statuses" "2.0.1"
escape-html "~1.0.3"
parseurl "~1.3.3" "serve-static@1.15.0":
send "0.18.0" "integrity" "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g=="
"resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz"
setprototypeof@1.2.0: "version" "1.15.0"
version "1.2.0" dependencies:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" "encodeurl" "~1.0.2"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== "escape-html" "~1.0.3"
"parseurl" "~1.3.3"
side-channel@^1.0.4: "send" "0.18.0"
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" "setprototypeof@1.2.0":
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== "integrity" "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
dependencies: "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
call-bind "^1.0.0" "version" "1.2.0"
get-intrinsic "^1.0.2"
object-inspect "^1.9.0" "side-channel@^1.0.4":
"integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="
sift@16.0.1: "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz"
version "16.0.1" "version" "1.0.4"
resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053" dependencies:
integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ== "call-bind" "^1.0.0"
"get-intrinsic" "^1.0.2"
simple-update-notifier@^1.0.7: "object-inspect" "^1.9.0"
version "1.1.0"
resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" "sift@16.0.1":
integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== "integrity" "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="
dependencies: "resolved" "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz"
semver "~7.0.0" "version" "16.0.1"
smart-buffer@^4.2.0: "simple-update-notifier@^1.0.7":
version "4.2.0" "integrity" "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg=="
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" "resolved" "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== "version" "1.1.0"
dependencies:
socks@^2.7.1: "semver" "~7.0.0"
version "2.7.1"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" "smart-buffer@^4.2.0":
integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== "integrity" "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
dependencies: "resolved" "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz"
ip "^2.0.0" "version" "4.2.0"
smart-buffer "^4.2.0"
"socks@^2.7.1":
sparse-bitfield@^3.0.3: "integrity" "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ=="
version "3.0.3" "resolved" "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz"
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" "version" "2.7.1"
integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== dependencies:
dependencies: "ip" "^2.0.0"
memory-pager "^1.0.2" "smart-buffer" "^4.2.0"
statuses@2.0.1: "sparse-bitfield@^3.0.3":
version "2.0.1" "integrity" "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" "resolved" "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== "version" "3.0.3"
dependencies:
streamsearch@^1.1.0: "memory-pager" "^1.0.2"
version "1.1.0"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" "statuses@2.0.1":
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== "integrity" "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
"resolved" "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
string_decoder@~1.1.1: "version" "2.0.1"
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" "streamsearch@^1.1.0":
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== "integrity" "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
dependencies: "resolved" "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
safe-buffer "~5.1.0" "version" "1.1.0"
strip-ansi@^3.0.0: "string_decoder@~1.1.1":
version "3.0.1" "integrity" "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== "version" "1.1.1"
dependencies: dependencies:
ansi-regex "^2.0.0" "safe-buffer" "~5.1.0"
supports-color@^2.0.0: "strip-ansi@^3.0.0":
version "2.0.0" "integrity" "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== "version" "3.0.1"
dependencies:
supports-color@^5.5.0: "ansi-regex" "^2.0.0"
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" "supports-color@^2.0.0":
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== "integrity" "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="
dependencies: "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
has-flag "^3.0.0" "version" "2.0.0"
to-regex-range@^5.0.1: "supports-color@^5.5.0":
version "5.0.1" "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== "version" "5.5.0"
dependencies: dependencies:
is-number "^7.0.0" "has-flag" "^3.0.0"
toidentifier@1.0.1: "to-regex-range@^5.0.1":
version "1.0.1" "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== "version" "5.0.1"
dependencies:
torch@^0.2.7: "is-number" "^7.0.0"
version "0.2.7"
resolved "https://registry.yarnpkg.com/torch/-/torch-0.2.7.tgz#ac4bc487e988ee582b383ece48fe0169e95443ad" "toidentifier@1.0.1":
integrity sha512-yTv7qWKGg00hMDv0pyBgRjubbf4eygzzrjKPKRC9rbPCKBF0jd+cxnzIoN+pCHgGf2EQbd0jGyy1X7h5BIqjEA== "integrity" "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
dependencies: "resolved" "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
chalk "^1.1.3" "version" "1.0.1"
touch@^3.1.0: "torch@^0.2.7":
version "3.1.0" "integrity" "sha512-yTv7qWKGg00hMDv0pyBgRjubbf4eygzzrjKPKRC9rbPCKBF0jd+cxnzIoN+pCHgGf2EQbd0jGyy1X7h5BIqjEA=="
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" "resolved" "https://registry.npmjs.org/torch/-/torch-0.2.7.tgz"
integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== "version" "0.2.7"
dependencies: dependencies:
nopt "~1.0.10" "chalk" "^1.1.3"
tr46@^3.0.0: "touch@^3.1.0":
version "3.0.0" "integrity" "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA=="
resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" "resolved" "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz"
integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== "version" "3.1.0"
dependencies: dependencies:
punycode "^2.1.1" "nopt" "~1.0.10"
type-is@^1.6.4, type-is@~1.6.18: "tr46@^3.0.0":
version "1.6.18" "integrity" "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" "resolved" "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== "version" "3.0.0"
dependencies: dependencies:
media-typer "0.3.0" "punycode" "^2.1.1"
mime-types "~2.1.24"
"type-is@^1.6.4", "type-is@~1.6.18":
typedarray@^0.0.6: "integrity" "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="
version "0.0.6" "resolved" "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" "version" "1.6.18"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== dependencies:
"media-typer" "0.3.0"
undefsafe@^2.0.5: "mime-types" "~2.1.24"
version "2.0.5"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" "typedarray@^0.0.6":
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== "integrity" "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
"resolved" "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
unpipe@1.0.0, unpipe@~1.0.0: "version" "0.0.6"
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" "undefsafe@^2.0.5":
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== "integrity" "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
"resolved" "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz"
util-deprecate@~1.0.1: "version" "2.0.5"
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" "unpipe@~1.0.0", "unpipe@1.0.0":
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== "integrity" "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
"resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
utils-merge@1.0.1: "version" "1.0.0"
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" "util-deprecate@~1.0.1":
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== "integrity" "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
"resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
uuid@^9.0.0: "version" "1.0.2"
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" "utils-merge@1.0.1":
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== "integrity" "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
"resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
vary@^1, vary@~1.1.2: "version" "1.0.1"
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" "uuid@^9.0.0":
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== "integrity" "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
"resolved" "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz"
webidl-conversions@^7.0.0: "version" "9.0.0"
version "7.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" "vary@^1", "vary@~1.1.2":
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== "integrity" "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
"resolved" "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
whatwg-url@^11.0.0: "version" "1.1.2"
version "11.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" "webidl-conversions@^7.0.0":
integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== "integrity" "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
dependencies: "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz"
tr46 "^3.0.0" "version" "7.0.0"
webidl-conversions "^7.0.0"
"whatwg-url@^11.0.0":
xtend@^4.0.0: "integrity" "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="
version "4.0.2" "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" "version" "11.0.0"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== dependencies:
"tr46" "^3.0.0"
yallist@^4.0.0: "webidl-conversions" "^7.0.0"
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" "xtend@^4.0.0":
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
"resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
"version" "4.0.2"
"yallist@^4.0.0":
"integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
"version" "4.0.0"
import os
from fastapi import APIRouter, File, HTTPException, Query,UploadFile from fastapi import APIRouter, File, HTTPException, Query,UploadFile
from pydantic import BaseModel from pydantic import BaseModel
import tensorflow as tf import tensorflow as tf
...@@ -11,12 +12,22 @@ from utils import mappings ...@@ -11,12 +12,22 @@ from utils import mappings
router = APIRouter() router = APIRouter()
logger = setup_logger() logger = setup_logger()
class ImageRequest(BaseModel): class ImageRequest(BaseModel):
image: UploadFile image: UploadFile
# Load your Keras model # Load your Keras model
# model = tf.keras.models.load_model('../ML_Models/sign_language_to_text/models/sign_language_model.h5') # model = tf.keras.models.load_model('../ML_Models/sign_language_to_text/models/sign_language_model.h5')
model= None model_file_path = '../ML_Models/sign_language_to_text/models/sign_language_model.h5'
# Check if the model file exists
if os.path.exists(model_file_path):
# Load the Keras model if the file exists
model = tf.keras.models.load_model(model_file_path)
else:
model = None
CLASSES = mappings.classes CLASSES = mappings.classes
NUM_CLASSES = len(mappings.classes) # number of classes NUM_CLASSES = len(mappings.classes) # number of classes
IMG_SIZE = 224 # image size IMG_SIZE = 224 # image size
...@@ -29,7 +40,6 @@ prediction_service = SignLanguagePredictionService(model, CLASSES, mappings,spee ...@@ -29,7 +40,6 @@ prediction_service = SignLanguagePredictionService(model, CLASSES, mappings,spee
@router.post("/upload/video", tags=["Sign Language"]) @router.post("/upload/video", tags=["Sign Language"])
async def upload_video(video: UploadFile = File(...)): async def upload_video(video: UploadFile = File(...)):
try: try:
file_location = f"files/{video.filename}" file_location = f"files/{video.filename}"
with open(file_location, "wb") as file: with open(file_location, "wb") as file:
file.write(video.file.read()) file.write(video.file.read())
...@@ -69,7 +79,4 @@ def predict_using_video(video_request: UploadFile = File(...), speed: int = Quer ...@@ -69,7 +79,4 @@ def predict_using_video(video_request: UploadFile = File(...), speed: int = Quer
return prediction_service.predict_sign_language_video_with_speed_levels(video_request, speed=speed) return prediction_service.predict_sign_language_video_with_speed_levels(video_request, speed=speed)
except Exception as e: except Exception as e:
logger.info(f"Error. {e}") logger.info(f"Error. {e}")
raise HTTPException( raise HTTPException(status_code=500, detail="Request Failed.")
status_code=500,
detail="Request Failed."
)
\ No newline at end of file
from datetime import datetime
import moviepy.editor as mp
import requests
import speech_recognition as sr
from fastapi import APIRouter, File, HTTPException, UploadFile
from fastapi.responses import JSONResponse
from pymongo.mongo_client import MongoClient
from bson import ObjectId
from core.logger import setup_logger
# Replace with your MongoDB Atlas credentials
username = "admin"
password = "JppbU6MZeHfOj7sp"
uri = f"mongodb+srv://{username}:{password}@researchmanagement-appl.vzhn4.mongodb.net/?retryWrites=true&w=majority"
client = MongoClient(uri)
db = client["test"]
items_collection = db["translated_items"]
items_collection_log = db["translated_items_log"]
TEMP_VIDEO_PATH = "C:/Users/himashara/Documents/SLIIT/1 SEMESTER/Research Project - IT4010/Research Project/2023-029/Project/Backend/Server_Python/resources/temp_video.mp4"
AUDIO_SAVE_PATH = "C:/Users/himashara/Documents/SLIIT/1 SEMESTER/Research Project - IT4010/Research Project/2023-029/Project/Backend/Server_Python/resources/audio.wav"
router = APIRouter()
logger = setup_logger()
# @router.get("/rest_pyton/items")
# async def read_root():
# return {"message": "Hello, World!"}
@router.get("/rest_pyton/items")
async def read_items():
items = []
for item in items_collection.find():
item_dict = dict(item)
item_dict['_id'] = str(item_dict['_id']) # Convert _id to a string
items.append(item_dict)
return {"items": items}
@router.post("/rest_pyton/uploaded_video")
async def uploaded_video(file: UploadFile = File(...)):
try:
# Process the uploaded video
video_content = await file.read()
temp_video_path = TEMP_VIDEO_PATH
with open(temp_video_path, "wb") as temp_video_file:
temp_video_file.write(video_content)
audio_save_path = AUDIO_SAVE_PATH
video = mp.VideoFileClip(temp_video_path)
audio = video.audio
audio.write_audiofile(audio_save_path)
r = sr.Recognizer()
with sr.AudioFile(audio_save_path) as source:
audio = r.record(source)
recognized_text = r.recognize_google(audio, language="si-LK")
translated_text_si = translate_text(recognized_text, "si")
translated_text_en = translate_text(recognized_text, "en")
translated_integer_si = " ".join(
str(unicode_to_int_mapping.get(word, "0"))
for word in translated_text_si.split()
)
print("Translated Integer (Si):", translated_integer_si)
# Send translated integer to MongoDB
send_to_mongodb(translated_integer_si)
return JSONResponse(
content={
"translated_text_si": translated_text_si,
"translated_text_en": translated_text_en,
}
)
# return JSONResponse(content={"translated_text_si": "test"})
except Exception as e:
return JSONResponse(content={"error": str(e)}, status_code=500)
unicode_to_int_mapping = {"මම": 1, "හෙට": 2, "යනවා": 3, "මං": 4}
def translate_text(text, target_language):
url = "https://translate.googleapis.com/translate_a/single"
params = {
"client": "gtx",
"sl": "auto",
"tl": target_language,
"dt": "t",
"q": text,
}
response = requests.get(url, params=params)
translation_data = response.json()
translated_text = translation_data[0][0][0]
return translated_text
# v1
# def send_to_mongodb(translated_integer_si):
# translated_item_data = {
# "translated_integer_si": translated_integer_si,
# "timestamp": datetime.utcnow(),
# }
# result = items_collection.insert_one(translated_item_data)
# if not result.inserted_id:
# raise HTTPException(status_code=500, detail="Failed to create translated item")
# v2
# def send_to_mongodb(translated_integer_si):
# translated_item_data = {
# "translated_integer_si": translated_integer_si,
# "timestamp": datetime.utcnow(),
# }
# # Save the previous record to the log before updating
# existing_record = items_collection.find_one()
# if existing_record:
# items_collection_log = db["translated_items_log"]
# items_collection_log.insert_one(existing_record)
# # Update the existing record or create a new one
# result = items_collection.replace_one({}, translated_item_data, upsert=True)
# if result.matched_count == 0 and result.modified_count == 0:
# raise HTTPException(
# status_code=500, detail="Failed to update or create translated item"
# )
# v3
def send_to_mongodb(translated_integer_si):
translated_item_data = {
"translated_integer_si": translated_integer_si,
"timestamp": datetime.utcnow(),
}
# Save the previous record to the log before updating
existing_record = items_collection.find_one()
if existing_record:
items_collection_log = db["translated_items_log"]
# Exclude the _id field to allow MongoDB to generate a new one
existing_record.pop("_id", None)
items_collection_log.insert_one(existing_record)
# Update the existing record or create a new one
result = items_collection.replace_one({}, translated_item_data, upsert=True)
if result.matched_count == 0 and result.modified_count == 0:
raise HTTPException(
status_code=500, detail="Failed to update or create translated item"
)
from fastapi import FastAPI, HTTPException
from pymongo.mongo_client import MongoClient
from pydantic import BaseModel
from typing import List
from bson import ObjectId
from datetime import datetime
app = FastAPI()
# Replace with your MongoDB Atlas credentials
username = "admin"
password = "JppbU6MZeHfOj7sp"
uri = f"mongodb+srv://{username}:{password}@researchmanagement-appl.vzhn4.mongodb.net/?retryWrites=true&w=majority"
client = MongoClient(uri)
db = client["test"]
items_collection = db["translated_items"]
class ItemCreate(BaseModel):
item_name: str
item_description: str
class Item(BaseModel):
item_name: str
item_description: str
_id: str
class TranslatedItemCreate(BaseModel):
translated_integer_si: str
@app.on_event("startup")
async def startup_db_client():
app.mongodb_client = MongoClient(uri)
try:
app.mongodb_client.admin.command("ping")
print("Pinged your deployment. You successfully connected to MongoDB!")
except Exception as e:
print(e)
@app.on_event("shutdown")
async def shutdown_db_client():
app.mongodb_client.close()
@app.get("/")
async def read_root():
return {"message": "FastAPI with MongoDB integration"}
# send tranlated integer to mongodb
@app.post("/translated_items/", response_model=TranslatedItemCreate)
async def create_translated_item(translated_item_create: TranslatedItemCreate):
translated_item_data = {
"translated_integer_si": translated_item_create.translated_integer_si,
"timestamp": datetime.utcnow(),
}
result = items_collection.insert_one(translated_item_data)
if result.inserted_id:
# return translated_item_data
return {**translated_item_data, "_id": str(result.inserted_id)}
else:
raise HTTPException(status_code=500, detail="Failed to create translated item")
@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item_update: ItemCreate):
item_object_id = ObjectId(item_id) # Convert item_id to ObjectId
update_data = {
"item_name": item_update.item_name,
"item_description": item_update.item_description,
}
result = items_collection.update_one({"_id": item_object_id}, {"$set": update_data})
if result.modified_count > 0:
updated_item = items_collection.find_one({"_id": item_object_id})
return {**updated_item, "_id": str(updated_item["_id"])}
else:
raise HTTPException(status_code=404, detail="Item not found")
@app.get("/items/", response_model=List[Item])
async def get_all_items():
items = list(items_collection.find())
items_with_string_id = [{**item, "_id": str(item["_id"])} for item in items]
print(items_with_string_id)
return items_with_string_id
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
from fastapi import FastAPI from fastapi import FastAPI
from controllers import translate_controler, users_controller from controllers import (
translate_controler,
users_controller,
video_to_sign_language_controller,
)
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from pymongo.mongo_client import MongoClient
from core.logger import setup_logger from core.logger import setup_logger
app = FastAPI()
# Replace with your MongoDB Atlas credentials
username = "admin"
password = "JppbU6MZeHfOj7sp"
uri = f"mongodb+srv://{username}:{password}@researchmanagement-appl.vzhn4.mongodb.net/?retryWrites=true&w=majority"
client = MongoClient(uri)
db = client["test"]
items_collection = db["translated_items"]
@app.on_event("startup")
async def startup_db_client():
app.mongodb_client = MongoClient(uri)
try:
app.mongodb_client.admin.command("ping")
print("Pinged your deployment. You successfully connected to MongoDB!")
except Exception as e:
print(e)
@app.on_event("shutdown")
async def shutdown_db_client():
app.mongodb_client.close()
app = FastAPI()
logger = setup_logger() logger = setup_logger()
app.include_router(users_controller.router) app.include_router(users_controller.router)
app.include_router(translate_controler.router) app.include_router(translate_controler.router)
app.include_router(video_to_sign_language_controller.router)
# Add cores middleware # Add cores middleware
...@@ -21,15 +50,26 @@ origins = [ ...@@ -21,15 +50,26 @@ origins = [
"http://localhost:8080", "http://localhost:8080",
"http://localhost:8004", "http://localhost:8004",
"http://localhost:3000", "http://localhost:3000",
"http://127.0.0.1:8000",
"127.0.0.1:55553",
"http://localhost:52823",
"http://localhost:53826",
"http://localhost:51373",
"http://localhost:51489",
"https://v6p9d9t4.ssl.hwcdn.net",
"https://64f66d39fdef493229b2ddd9--lambent-unicorn-97396a.netlify.app"
] ]
app.add_middleware(CORSMiddleware, app.add_middleware(
CORSMiddleware,
allow_origins=origins, allow_origins=origins,
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"]) allow_headers=["*"],
)
@app.get('/') @app.get("/")
async def root(): async def root():
url = app.docs_url or '/docs' url = app.docs_url or "/docs"
return RedirectResponse(url) return RedirectResponse(url)
{
"systemParams": "win32-x64-93",
"modulesFolders": [],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],
"artifacts": {}
}
\ No newline at end of file
...@@ -3,3 +3,8 @@ uvicorn ...@@ -3,3 +3,8 @@ uvicorn
python-multipart==0.0.6 python-multipart==0.0.6
tensorflow==2.12.0 tensorflow==2.12.0
opencv-python==4.7.0.72 opencv-python==4.7.0.72
moviepy==1.0.3
SpeechRecognition==3.10.0
tk==0.1.0
requests==2.31.0
pymongo==4.5.0
\ No newline at end of file
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
"react-table-sticky": "^1.1.3", "react-table-sticky": "^1.1.3",
"react-timer-hook": "^3.0.5", "react-timer-hook": "^3.0.5",
"react-to-print": "^2.14.12", "react-to-print": "^2.14.12",
"react-unity-webgl": "^9.4.3",
"react-webcam": "^7.1.1", "react-webcam": "^7.1.1",
"react-window": "^1.8.9", "react-window": "^1.8.9",
"react-zoom-pan-pinch": "^3.0.7", "react-zoom-pan-pinch": "^3.0.7",
......
...@@ -56,17 +56,27 @@ export const JWTProvider = ({ children }: { children: React.ReactElement }) => { ...@@ -56,17 +56,27 @@ export const JWTProvider = ({ children }: { children: React.ReactElement }) => {
const init = async () => { const init = async () => {
try { try {
const serviceToken = window.localStorage.getItem('serviceToken'); const serviceToken = window.localStorage.getItem('serviceToken');
console.log(verifyToken(serviceToken!));
if (serviceToken && verifyToken(serviceToken)) { if (serviceToken && verifyToken(serviceToken)) {
setSession(serviceToken); setSession(serviceToken);
// const response = await axios.get('/api/account/me');
// const { user } = response.data; // Set the token in your Axios instance for future requests
axiosServices.defaults.headers.common['Authorization'] = `Bearer ${serviceToken}`;
// Make the API request
const response = await axiosServices.get('/rest_node/user/current-user');
const { user } = response.data;
dispatch({ dispatch({
type: LOGIN, type: LOGIN,
payload: { payload: {
isLoggedIn: true, isLoggedIn: true,
// user user: {
id: user._id,
email: user.email,
name: `${user.firstName} ${user.lastName}`,
role: user.type
}
} }
}); });
} else { } else {
......
import { curriculumType } from "types/curriculum";
export const curriculums: curriculumType[] = [
{
"curriculumCode": "01",
"curriculumLevel": 1,
"curriculumDescription": "This curriculum teaches basic sign language skills to help beginners communicate effectively using sign language.",
"curriculumTitle": "Basic Sign Language Skills",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
"_id": "1",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"curriculumMark": 100,
"tutorials": [
{
"tutorialCode": "01",
"tutorialTitle": "Numbers and Counting",
"tutorialDescription": "In this tutorial, you'll discover how to express numbers visually using simple hand gestures. Each number has a unique sign that involves specific finger placements and hand movements. We'll break down each number step by step, providing you with clear instructions, images, and videos to help you learn effectively.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1GeFzoy3xt8UnfCQE3IPVjPXoAg7GAWgf",
"_id": "1",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 100,
"taskItems": [
{
"_id": "1",
"title": "Learn Number One",
"description": "In this lesson, you will learn how to sign the number one. Understanding this basic sign is crucial for counting and expressing singular items or concepts in sign language. Practice the hand shape, movement, and facial expression associated with the sign to improve your fluency.",
"howToDo": [
"- Extend your index finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=17sHGfW9zip8xAwbRtUihzxkseKq-Qn7q",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "2",
"title": "Learn Number Two",
"description": "In this lesson, you will learn how to sign the number two. Mastering this sign is essential for counting and expressing pairs or dual concepts in sign language. Pay attention to the hand shape, movement, and facial expression involved in signing the number two to enhance your signing skills.",
"howToDo": [
"- Extend your index and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Nm-we15Rrr04ovRC1sr-ZVMNHbnALRm2",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "3",
"title": "Learn Number Three",
"description": "In this lesson, you will learn how to sign the number three in sign language. Mastering this sign is essential for expressing the quantity or position of three items. Pay attention to the hand shape, movement, and facial expression involved in signing the number three to enhance your signing skills.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1mKY8D1utbqm8flnNM7DZRKtuPQDXqFSm",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "4",
"title": "Learn Number Four",
"description": "In this lesson, you will learn how to sign the number four in sign language. This sign is commonly used for counting or indicating the quantity or position of four items. Focus on the hand shape, movement, and expression to accurately convey the number four in sign language.",
"howToDo": [
"- Extend your thumb, index, middle, and ring fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1VtbHehsxbOC04fVR6_Ca6HDv6csH17SJ",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "5",
"title": "Learn Number Five",
"description": "In this lesson, you will learn how to sign the number five in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of five. Practice the hand shape, movement, and facial expression to effectively communicate the number five in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Keep your thumb resting on the side of your palm.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1G6qx4dhHTKUPvNag0R3qlDJugNOgcTqM",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "6",
"title": "Learn Number Six",
"description": "In this lesson, you will learn how to sign the number six in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of six. Pay attention to the hand shape, movement, and expression involved in signing the number six to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and pinky finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Q2TbcPTx8KuLp4v2mPL_7GHO0l52DZXw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "7",
"title": "Learn Number Seven",
"description": "In this lesson, you will learn how to sign the number seven in sign language. Mastering this sign is essential for counting, expressing quantities, or representing the concept of seven. Focus on the hand shape, movement, and facial expression to accurately convey the number seven in sign language.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep your thumb, pinky, and pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Jwt1TqXO1L7t3JFqQYzKL4S4GCuqULJ1",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "8",
"title": "Learn Number Eight",
"description": "In this lesson, you will learn how to sign the number eight in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of eight. Practice the hand shape, movement, and expression to effectively communicate the number eight in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Cross your index and middle fingers over your ring and pinky fingers.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1zSf4hmqIUCcfebgoD6DTWmJ3NxY36LJL",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "9",
"title": "Learn Number Nine",
"description": "In this lesson, you will learn how to sign the number nine in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of nine. Pay attention to the hand shape, movement, and expression involved in signing the number nine to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and all your fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=16WB1Ifhq_ozKOO-ehfIqVRB6oC3B5STw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "10",
"title": "Learn Number Ten",
"description": "In this lesson, you will learn how to sign the number ten in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of ten. Focus on the hand shape, movement, and facial expression to accurately convey the number ten in sign language.",
"howToDo": [
"- Extend your thumb, index, and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=11tCYFYjdVrr5LIFGyzOrIUg8bTURATZh",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
}
]
},
{
"tutorialCode": "02",
"tutorialTitle": "Everyday Vocabulary",
"tutorialDescription": "Teach signs for everyday objects and activities, such as eat, drink, sleep, book, pen, etc.\nIntroduce signs for common words used in daily life.\nProvide visual demonstrations and interactive exercises for learners to practice using these signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1QqmeBBiAojz7jaHUUdQGLyqUVR-mKSsy",
"taskItems": [],
"_id": "2",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
},
{
"tutorialCode": "03",
"tutorialTitle": "Family Signs",
"tutorialDescription": "Teach signs for family members, such as mother, father, sister, brother, etc.\nIntroduce signs for common family-related words, such as family, love, and home.\nProvide visual demonstrations and practice exercises for learners to practice these family signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1_b3-0HAAWu5Ze20IAAKWxUSUS-fac6Dg",
"taskItems": [],
"_id": "3",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
},
{
"tutorialCode": "04",
"tutorialTitle": "Basic Conversational Phrases",
"tutorialDescription": "Teach simple conversational phrases, such as \"What is your name?\" or \"How are you?\"\nIntroduce signs for common question words and phrases.\nProvide visual demonstrations and practice exercises for learners to practice these conversational phrases.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1McSxkqPb7ZnlsDKfZfTj6OTS5GvXXKFE",
"taskItems": [],
"_id": "4",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
}
]
},
{
"curriculumCode": "02",
"curriculumLevel": 2,
"curriculumTitle": "Intermediate Sign Language Skills",
"curriculumDescription": "This curriculum focuses on building intermediate sign language skills, allowing learners to engage in more complex conversations and interactions using sign language.",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1b5C6VNO55k3Wj6DJ-vJiUFFEuQnXs5Jo",
"tutorials": [],
"_id": "2",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"curriculumMark": 0,
},
{
"curriculumCode": "03",
"curriculumLevel": 3,
"curriculumTitle": "Advance Sign Language Skills",
"curriculumDescription": "This curriculum is designed for those who already have a solid foundation in sign language. It covers advanced topics, nuances, and cultural aspects of sign language communication.",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1k-CtiCkM3efhmTBet-JZt2izxVrAdBL3",
"tutorials": [],
"_id": "3",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"curriculumMark": 100,
}
]
export interface StatusType {
id: number
code: string
description: string
}
// ==============================|| DATA - Status ||============================== //
const status: readonly StatusType[] = [
{ id: 1, code: "Active", description: "Active" },
{ id: 2, code: "New", description: "New" },
{ id: 3, code: "Pending", description: "Pending" },
{ id: 4, code: "Hold", description: "Hold" },
{ id: 5, code: "Rejected", description: "Rejected" },
];
export default status;
import { taskItemType } from "types/taskItem";
export const taskItems: taskItemType[] = [
{
"_id": "1",
"title": "Learn Number One",
"description": "In this lesson, you will learn how to sign the number one. Understanding this basic sign is crucial for counting and expressing singular items or concepts in sign language. Practice the hand shape, movement, and facial expression associated with the sign to improve your fluency.",
"howToDo": [
"- Extend your index finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=17sHGfW9zip8xAwbRtUihzxkseKq-Qn7q",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "2",
"title": "Learn Number Two",
"description": "In this lesson, you will learn how to sign the number two. Mastering this sign is essential for counting and expressing pairs or dual concepts in sign language. Pay attention to the hand shape, movement, and facial expression involved in signing the number two to enhance your signing skills.",
"howToDo": [
"- Extend your index and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Nm-we15Rrr04ovRC1sr-ZVMNHbnALRm2",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "3",
"title": "Learn Number Three",
"description": "In this lesson, you will learn how to sign the number three in sign language. Mastering this sign is essential for expressing the quantity or position of three items. Pay attention to the hand shape, movement, and facial expression involved in signing the number three to enhance your signing skills.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1mKY8D1utbqm8flnNM7DZRKtuPQDXqFSm",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "4",
"title": "Learn Number Four",
"description": "In this lesson, you will learn how to sign the number four in sign language. This sign is commonly used for counting or indicating the quantity or position of four items. Focus on the hand shape, movement, and expression to accurately convey the number four in sign language.",
"howToDo": [
"- Extend your thumb, index, middle, and ring fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1VtbHehsxbOC04fVR6_Ca6HDv6csH17SJ",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "5",
"title": "Learn Number Five",
"description": "In this lesson, you will learn how to sign the number five in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of five. Practice the hand shape, movement, and facial expression to effectively communicate the number five in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Keep your thumb resting on the side of your palm.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1G6qx4dhHTKUPvNag0R3qlDJugNOgcTqM",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "6",
"title": "Learn Number Six",
"description": "In this lesson, you will learn how to sign the number six in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of six. Pay attention to the hand shape, movement, and expression involved in signing the number six to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and pinky finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Q2TbcPTx8KuLp4v2mPL_7GHO0l52DZXw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "7",
"title": "Learn Number Seven",
"description": "In this lesson, you will learn how to sign the number seven in sign language. Mastering this sign is essential for counting, expressing quantities, or representing the concept of seven. Focus on the hand shape, movement, and facial expression to accurately convey the number seven in sign language.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep your thumb, pinky, and pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Jwt1TqXO1L7t3JFqQYzKL4S4GCuqULJ1",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "8",
"title": "Learn Number Eight",
"description": "In this lesson, you will learn how to sign the number eight in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of eight. Practice the hand shape, movement, and expression to effectively communicate the number eight in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Cross your index and middle fingers over your ring and pinky fingers.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1zSf4hmqIUCcfebgoD6DTWmJ3NxY36LJL",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "9",
"title": "Learn Number Nine",
"description": "In this lesson, you will learn how to sign the number nine in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of nine. Pay attention to the hand shape, movement, and expression involved in signing the number nine to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and all your fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=16WB1Ifhq_ozKOO-ehfIqVRB6oC3B5STw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "10",
"title": "Learn Number Ten",
"description": "In this lesson, you will learn how to sign the number ten in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of ten. Focus on the hand shape, movement, and facial expression to accurately convey the number ten in sign language.",
"howToDo": [
"- Extend your thumb, index, and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=11tCYFYjdVrr5LIFGyzOrIUg8bTURATZh",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
}
]
\ No newline at end of file
import { Tutorial, tutorialType } from "types/tutorial";
export const tutorials: tutorialType[] = [
{
"tutorialCode": "01",
"tutorialTitle": "Numbers and Counting in Sign Language",
"tutorialDescription": "In this tutorial, you'll discover how to express numbers visually using simple hand gestures. Each number has a unique sign that involves specific finger placements and hand movements. We'll break down each number step by step, providing you with clear instructions, images, and videos to help you learn effectively.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1GeFzoy3xt8UnfCQE3IPVjPXoAg7GAWgf",
"_id": "1",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 100,
"taskItems": [
{
"_id": "1",
"title": "Learn Number One",
"description": "In this lesson, you will learn how to sign the number one. Understanding this basic sign is crucial for counting and expressing singular items or concepts in sign language. Practice the hand shape, movement, and facial expression associated with the sign to improve your fluency.",
"howToDo": [
"- Extend your index finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=17sHGfW9zip8xAwbRtUihzxkseKq-Qn7q",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "2",
"title": "Learn Number Two",
"description": "In this lesson, you will learn how to sign the number two. Mastering this sign is essential for counting and expressing pairs or dual concepts in sign language. Pay attention to the hand shape, movement, and facial expression involved in signing the number two to enhance your signing skills.",
"howToDo": [
"- Extend your index and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Nm-we15Rrr04ovRC1sr-ZVMNHbnALRm2",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "3",
"title": "Learn Number Three",
"description": "In this lesson, you will learn how to sign the number three in sign language. Mastering this sign is essential for expressing the quantity or position of three items. Pay attention to the hand shape, movement, and facial expression involved in signing the number three to enhance your signing skills.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1mKY8D1utbqm8flnNM7DZRKtuPQDXqFSm",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "4",
"title": "Learn Number Four",
"description": "In this lesson, you will learn how to sign the number four in sign language. This sign is commonly used for counting or indicating the quantity or position of four items. Focus on the hand shape, movement, and expression to accurately convey the number four in sign language.",
"howToDo": [
"- Extend your thumb, index, middle, and ring fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1VtbHehsxbOC04fVR6_Ca6HDv6csH17SJ",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "5",
"title": "Learn Number Five",
"description": "In this lesson, you will learn how to sign the number five in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of five. Practice the hand shape, movement, and facial expression to effectively communicate the number five in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Keep your thumb resting on the side of your palm.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1G6qx4dhHTKUPvNag0R3qlDJugNOgcTqM",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "6",
"title": "Learn Number Six",
"description": "In this lesson, you will learn how to sign the number six in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of six. Pay attention to the hand shape, movement, and expression involved in signing the number six to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and pinky finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Q2TbcPTx8KuLp4v2mPL_7GHO0l52DZXw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "7",
"title": "Learn Number Seven",
"description": "In this lesson, you will learn how to sign the number seven in sign language. Mastering this sign is essential for counting, expressing quantities, or representing the concept of seven. Focus on the hand shape, movement, and facial expression to accurately convey the number seven in sign language.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep your thumb, pinky, and pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Jwt1TqXO1L7t3JFqQYzKL4S4GCuqULJ1",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "8",
"title": "Learn Number Eight",
"description": "In this lesson, you will learn how to sign the number eight in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of eight. Practice the hand shape, movement, and expression to effectively communicate the number eight in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Cross your index and middle fingers over your ring and pinky fingers.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1zSf4hmqIUCcfebgoD6DTWmJ3NxY36LJL",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "9",
"title": "Learn Number Nine",
"description": "In this lesson, you will learn how to sign the number nine in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of nine. Pay attention to the hand shape, movement, and expression involved in signing the number nine to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and all your fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=16WB1Ifhq_ozKOO-ehfIqVRB6oC3B5STw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
},
{
"_id": "10",
"title": "Learn Number Ten",
"description": "In this lesson, you will learn how to sign the number ten in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of ten. Focus on the hand shape, movement, and facial expression to accurately convey the number ten in sign language.",
"howToDo": [
"- Extend your thumb, index, and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=11tCYFYjdVrr5LIFGyzOrIUg8bTURATZh",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10
}
]
},
{
"tutorialCode": "02",
"tutorialTitle": "Everyday Vocabulary in Sign Language",
"tutorialDescription": "Teach signs for everyday objects and activities, such as eat, drink, sleep, book, pen, etc.\nIntroduce signs for common words used in daily life.\nProvide visual demonstrations and interactive exercises for learners to practice using these signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1QqmeBBiAojz7jaHUUdQGLyqUVR-mKSsy",
"taskItems": [],
"_id": "2",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
},
{
"tutorialCode": "03",
"tutorialTitle": "Family Signs in Sign Language",
"tutorialDescription": "Teach signs for family members, such as mother, father, sister, brother, etc.\nIntroduce signs for common family-related words, such as family, love, and home.\nProvide visual demonstrations and practice exercises for learners to practice these family signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1_b3-0HAAWu5Ze20IAAKWxUSUS-fac6Dg",
"taskItems": [],
"_id": "3",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
},
{
"tutorialCode": "04",
"tutorialTitle": "Basic Conversational Phrases in Sign Language",
"tutorialDescription": "Teach simple conversational phrases, such as \"What is your name?\" or \"How are you?\"\nIntroduce signs for common question words and phrases.\nProvide visual demonstrations and practice exercises for learners to practice these conversational phrases.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1McSxkqPb7ZnlsDKfZfTj6OTS5GvXXKFE",
"taskItems": [],
"_id": "4",
"status": 1,
"createdBy": "Nuwan Gamage",
"createdAt": new Date("2023-08-30T12:00:00Z"),
"tutorialMark": 0,
}
]
export const tutorialReqOb: Tutorial = {
"tutorialCode": "01-SAMPLE",
"tutorialTitle": "Numbers and Counting in Sign Language",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1GeFzoy3xt8UnfCQE3IPVjPXoAg7GAWgf",
"tutorialDescription": "In this tutorial, you'll discover how to express numbers visually using simple hand gestures. Each number has a unique sign that involves specific finger placements and hand movements. We'll break down each number step by step, providing you with clear instructions, images, and videos to help you learn effectively.",
"taskItems": [
{
"title": "Learn Number One",
"description": "In this lesson, you will learn how to sign the number one. Understanding this basic sign is crucial for counting and expressing singular items or concepts in sign language. Practice the hand shape, movement, and facial expression associated with the sign to improve your fluency.",
"howToDo": [
"- Extend your index finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=17sHGfW9zip8xAwbRtUihzxkseKq-Qn7q",
"referenceVideo": "",
"taskItemMark": 10
}
],
"createdBy": "Nuwan Gamage"
}
\ No newline at end of file
import { userProgressType } from "types/userProgress";
export const userProgress: userProgressType = {
"_id": "64f1f99f9a5bff5bfdb1bbc9",
"userId": "64f087fda8db35e2f70753ab",
"curriculums": [
{
"curriculumCode": "01",
"curriculumLevel": 1,
"curriculumTitle": "Basic Sign Language Skills",
"curriculumDescription": "This curriculum teaches basic sign language skills to help beginners communicate effectively using sign language.",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
"curriculumMark": 100,
"curriculumMarkUser": 24,
"curriculumSpentTime": 15,
"tutorials": [
{
"tutorialCode": "01",
"tutorialTitle": "Numbers and Counting",
"tutorialDescription": "In this tutorial, you'll discover how to express numbers visually using simple hand gestures. Each number has a unique sign that involves specific finger placements and hand movements. We'll break down each number step by step, providing you with clear instructions, images, and videos to help you learn effectively.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1GeFzoy3xt8UnfCQE3IPVjPXoAg7GAWgf",
"tutorialMarks": 100,
"tutorialMarkUser": 24,
"tutorialSpentTime": 15,
"taskItems": [
{
"title": "Learn Number One",
"description": "In this lesson, you will learn how to sign the number one. Understanding this basic sign is crucial for counting and expressing singular items or concepts in sign language. Practice the hand shape, movement, and facial expression associated with the sign to improve your fluency.",
"howToDo": [
"- Extend your index finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=17sHGfW9zip8xAwbRtUihzxkseKq-Qn7q",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 8,
"taskItemSpentTime": 5
},
{
"title": "Learn Number Two",
"description": "In this lesson, you will learn how to sign the number two. Mastering this sign is essential for counting and expressing pairs or dual concepts in sign language. Pay attention to the hand shape, movement, and facial expression involved in signing the number two to enhance your signing skills.",
"howToDo": [
"- Extend your index and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Nm-we15Rrr04ovRC1sr-ZVMNHbnALRm2",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 8,
"taskItemSpentTime": 5
},
{
"title": "Learn Number Three",
"description": "In this lesson, you will learn how to sign the number three in sign language. Mastering this sign is essential for expressing the quantity or position of three items. Pay attention to the hand shape, movement, and facial expression involved in signing the number three to enhance your signing skills.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1mKY8D1utbqm8flnNM7DZRKtuPQDXqFSm",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 8,
"taskItemSpentTime": 5
},
{
"title": "Learn Number Four",
"description": "In this lesson, you will learn how to sign the number four in sign language. This sign is commonly used for counting or indicating the quantity or position of four items. Focus on the hand shape, movement, and expression to accurately convey the number four in sign language.",
"howToDo": [
"- Extend your thumb, index, middle, and ring fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1VtbHehsxbOC04fVR6_Ca6HDv6csH17SJ",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Five",
"description": "In this lesson, you will learn how to sign the number five in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of five. Practice the hand shape, movement, and facial expression to effectively communicate the number five in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Keep your thumb resting on the side of your palm.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1G6qx4dhHTKUPvNag0R3qlDJugNOgcTqM",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Six",
"description": "In this lesson, you will learn how to sign the number six in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of six. Pay attention to the hand shape, movement, and expression involved in signing the number six to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and pinky finger straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Q2TbcPTx8KuLp4v2mPL_7GHO0l52DZXw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Seven",
"description": "In this lesson, you will learn how to sign the number seven in sign language. Mastering this sign is essential for counting, expressing quantities, or representing the concept of seven. Focus on the hand shape, movement, and facial expression to accurately convey the number seven in sign language.",
"howToDo": [
"- Extend your index, middle, and ring fingers straight up.",
"- Keep your thumb, pinky, and pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1Jwt1TqXO1L7t3JFqQYzKL4S4GCuqULJ1",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Eight",
"description": "In this lesson, you will learn how to sign the number eight in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of eight. Practice the hand shape, movement, and expression to effectively communicate the number eight in sign language.",
"howToDo": [
"- Extend all your fingers straight up.",
"- Cross your index and middle fingers over your ring and pinky fingers.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=1zSf4hmqIUCcfebgoD6DTWmJ3NxY36LJL",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Nine",
"description": "In this lesson, you will learn how to sign the number nine in sign language. Mastering this sign is crucial for counting, expressing quantities, or representing the concept of nine. Pay attention to the hand shape, movement, and expression involved in signing the number nine to enhance your signing proficiency.",
"howToDo": [
"- Extend your thumb and all your fingers straight up.",
"- Keep your pinky finger folded.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=16WB1Ifhq_ozKOO-ehfIqVRB6oC3B5STw",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
},
{
"title": "Learn Number Ten",
"description": "In this lesson, you will learn how to sign the number ten in sign language. This sign is commonly used for counting, indicating quantities, or representing the concept of ten. Focus on the hand shape, movement, and facial expression to accurately convey the number ten in sign language.",
"howToDo": [
"- Extend your thumb, index, and middle fingers straight up.",
"- Keep the rest of your fingers closed.",
"- Hold your hand in front of your chest."
],
"referenceImage": "https://drive.google.com/uc?export=view&id=11tCYFYjdVrr5LIFGyzOrIUg8bTURATZh",
"referenceVideo": "https://example.com/number_seven_video.mp4",
"taskItemMark": 10,
"taskItemMarkUser": 0,
"taskItemSpentTime": 0
}
]
},
{
"tutorialCode": "02",
"tutorialTitle": "Everyday Vocabulary",
"tutorialDescription": "Teach signs for everyday objects and activities, such as eat, drink, sleep, book, pen, etc.\nIntroduce signs for common words used in daily life.\nProvide visual demonstrations and interactive exercises for learners to practice using these signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1QqmeBBiAojz7jaHUUdQGLyqUVR-mKSsy",
"tutorialMarks": 0,
"tutorialMarkUser": 0,
"tutorialSpentTime": 0,
"taskItems": []
},
{
"tutorialCode": "03",
"tutorialTitle": "Family Signs",
"tutorialDescription": "Teach signs for family members, such as mother, father, sister, brother, etc.\nIntroduce signs for common family-related words, such as family, love, and home.\nProvide visual demonstrations and practice exercises for learners to practice these family signs.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1_b3-0HAAWu5Ze20IAAKWxUSUS-fac6Dg",
"tutorialMarks": 0,
"tutorialMarkUser": 0,
"tutorialSpentTime": 0,
"taskItems": []
},
{
"tutorialCode": "04",
"tutorialTitle": "Basic Conversational Phrases",
"tutorialDescription": "Teach simple conversational phrases, such as \"What is your name?\" or \"How are you?\"\nIntroduce signs for common question words and phrases.\nProvide visual demonstrations and practice exercises for learners to practice these conversational phrases.",
"tutorialImage": "https://drive.google.com/uc?export=view&id=1McSxkqPb7ZnlsDKfZfTj6OTS5GvXXKFE",
"tutorialMarks": 0,
"tutorialMarkUser": 0,
"tutorialSpentTime": 0,
"taskItems": []
}
]
},
],
"totalCurriculumsMarks": 24,
"totalCurriculumSpentTime": 15,
"status": 1,
"createdAt": new Date("2023-08-30T12:00:00Z"),
"updatedAt": new Date("2023-08-30T12:00:00Z")
}
\ No newline at end of file
...@@ -10,7 +10,7 @@ import Message from './Message'; ...@@ -10,7 +10,7 @@ import Message from './Message';
import Notification from './Notification'; import Notification from './Notification';
import Profile from './Profile'; import Profile from './Profile';
import Search from './Search'; 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';
...@@ -42,7 +42,7 @@ const HeaderContent = () => { ...@@ -42,7 +42,7 @@ const HeaderContent = () => {
<Notification /> <Notification />
<Message /> <Message />
{/* <Customization /> */} <Customization />
{!downLG && <Profile />} {!downLG && <Profile />}
{downLG && <MobileSection />} {downLG && <MobileSection />}
</> </>
......
...@@ -3,19 +3,20 @@ import { FormattedMessage } from 'react-intl'; ...@@ -3,19 +3,20 @@ import { FormattedMessage } from 'react-intl';
// assets // assets
import { import {
AudioOutlined,
BookOutlined, BookOutlined,
CarryOutOutlined, CarryOutOutlined,
CreditCardOutlined, CreditCardOutlined,
FastForwardOutlined,
FileTextOutlined, FileTextOutlined,
LoginOutlined, LoginOutlined,
RedditOutlined,
RocketOutlined, RocketOutlined,
ShoppingOutlined, ShoppingOutlined,
TeamOutlined, TeamOutlined,
TranslationOutlined, TranslationOutlined,
UserOutlined, UserOutlined,
AudioOutlined,
VideoCameraOutlined, VideoCameraOutlined,
RedditOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
// type // type
...@@ -33,9 +34,10 @@ const icons = { ...@@ -33,9 +34,10 @@ const icons = {
RocketOutlined, RocketOutlined,
BookOutlined, BookOutlined,
TranslationOutlined, TranslationOutlined,
AudioOutlined, FastForwardOutlined,
VideoCameraOutlined,
RedditOutlined, RedditOutlined,
AudioOutlined,
VideoCameraOutlined
}; };
// ==============================|| MENU ITEMS - SUPPORT ||============================== // // ==============================|| MENU ITEMS - SUPPORT ||============================== //
...@@ -80,6 +82,20 @@ const application: NavItemType = { ...@@ -80,6 +82,20 @@ const application: NavItemType = {
icon: icons.TranslationOutlined, icon: icons.TranslationOutlined,
url: '/ssl-translate/process', url: '/ssl-translate/process',
}, },
{
id: 'video-to-sign-language',
title: <FormattedMessage id="video-to-sign-language" />,
type: 'collapse',
icon: icons.RedditOutlined,
children: [
{
id: 'video-translate',
title: <FormattedMessage id="video-translate" />,
type: 'item',
url: '/video-to-sign-language/VideoTranslate',
}
]
},
{ {
id: 'emotion-detection', id: 'emotion-detection',
title: <FormattedMessage id="emotion-detection" />, title: <FormattedMessage id="emotion-detection" />,
...@@ -137,6 +153,12 @@ const application: NavItemType = { ...@@ -137,6 +153,12 @@ const application: NavItemType = {
type: 'item', type: 'item',
url: '/learning-management/curriculums-subscribed', url: '/learning-management/curriculums-subscribed',
}, },
{
id: 'learning-curriculums-subscribed-tutorial',
title: <FormattedMessage id="learning-curriculums-subscribed-tutorial" />,
type: 'item',
url: '/learning-management/curriculums-subscribed-tutorial/0/0',
},
{ {
id: 'learning-lead-board', id: 'learning-lead-board',
title: <FormattedMessage id="learning-lead-board" />, title: <FormattedMessage id="learning-lead-board" />,
......
// material-ui // material-ui
// project import // project import
// ==============================|| Dashboard ||============================== // // ==============================|| Dashboard ||============================== //
const Dashboard = () => ( const Dashboard = () => {
return (
<> <>
</> </>
); );
}
export default Dashboard; export default Dashboard;
import { useState } from 'react';
// material-ui // material-ui
import { Grid } from '@mui/material'; import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import { Card, CardContent, CardHeader, Collapse, Grid, IconButton, Typography } from '@mui/material';
// third-party // third-party
...@@ -15,11 +17,67 @@ import WelcomeBanner from 'sections/learning-management/WelcomeBanner'; ...@@ -15,11 +17,67 @@ import WelcomeBanner from 'sections/learning-management/WelcomeBanner';
// ==============================|| Dashboard ||============================== // // ==============================|| Dashboard ||============================== //
const Dashboard = () => { const Dashboard = () => {
const [expanded, setExpanded] = useState(false);
const handleExpandClick = () => {
setExpanded(!expanded);
};
return ( return (
<Grid container rowSpacing={4.5} columnSpacing={3}> <Grid container rowSpacing={2} columnSpacing={3}>
<Grid item xs={12}> <Grid item xs={12}>
<WelcomeBanner /> <WelcomeBanner />
</Grid> </Grid>
<Grid md={12} item>
<Card>
<CardHeader
title="Learn Sign Language Curriculums"
subheader="Building a Solid Foundation, Enhancing Skills, and Mastering Sign Language"
action={
<IconButton
aria-expanded={expanded}
aria-label="show more"
onClick={handleExpandClick}
>
{expanded ? <ArrowUpOutlined /> : <ArrowDownOutlined />}
</IconButton>
}
/>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography variant="body1">
Explore the world of sign language with our comprehensive Curriculum offerings. We provide three levels of sign language Curriculums designed to cater to learners of varying proficiency levels.
</Typography>
<Typography variant="subtitle1" sx={{ mt: 3 }}>
1. Base Level - Learn Sign Language:
</Typography>
<Typography variant="body2" sx={{ mt: 3 }}>
Start your sign language journey with our Base Level Curriculum. Perfect for beginners, this Curriculum offers essential sign language skills, including basic vocabulary, grammar, and sentence structures. Through interactive lessons and hands-on practice, you'll learn to express yourself through gestures and facial expressions, enabling effective communication with the deaf and hard of hearing community. Join us today and begin breaking down communication barriers.
</Typography>
<Typography variant="subtitle1" sx={{ mt: 3 }}>
2. Medium Level - Enhancing Sign Language Skills:
</Typography>
<Typography variant="body2" sx={{ mt: 3 }}>
Take your sign language skills to the next level with our Medium Level Curriculum. Designed for learners with some basic knowledge of sign language, this Curriculum focuses on expanding vocabulary, improving grammar usage, and honing expressive abilities. Engage in challenging yet rewarding lessons, interactive exercises, role-playing scenarios, and conversations to strengthen fluency. By delving deeper into sign language communication, including idiomatic expressions and storytelling techniques, you'll be able to connect with the deaf community on a deeper level.
</Typography>
<Typography variant="subtitle1" sx={{ mt: 3 }}>
3. Advanced Level - Mastering Sign Language:
</Typography>
<Typography variant="body2" sx={{ mt: 3 }}>
Become a proficient sign language user with our Advanced Level Curriculum. This comprehensive Curriculum is designed for experienced sign language learners seeking mastery. Dive into advanced topics such as complex grammar structures, specialized vocabulary, and cultural nuances. Through immersive activities, real-life simulations, and in-depth discussions, you'll refine your receptive and expressive skills. Explore various sign language modalities and gain a deep understanding of different signing systems. With personalized feedback and guidance from expert instructors, our Advanced Level Curriculum equips you to engage confidently in diverse sign language contexts.
</Typography>
<Typography variant="subtitle2" sx={{ mt: 3 }}>
Whether you're starting from scratch or aiming to enhance your existing sign language skills, our Curriculums offer a supportive learning environment and the opportunity to build connections with the deaf community. Join us today and embark on your sign language journey!
</Typography>
</CardContent>
</Collapse>
</Card>
</Grid>
</Grid> </Grid>
) )
} }
......
import { useEffect, useState } from 'react';
// material-ui // material-ui
import {
// third-party Accordion, AccordionDetails, AccordionSummary,
Box,
FormControl,
Grid,
MenuItem,
Pagination,
Select,
SelectChangeEvent,
Slide,
Stack,
Theme,
Typography,
useMediaQuery
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
// project import // project import
import MainCard from 'components/MainCard'; import usePagination from 'hooks/usePagination';
import ScrollX from 'components/ScrollX'; import { GlobalFilter } from 'utils/react-table';
// types
// assets // assets
import { BookOutlined } from '@ant-design/icons';
//types import useAuth from 'hooks/useAuth';
import CurriculumSection from 'sections/learning-management/learning-curriculums-subscribed/CurriculumSection';
import EmptyCurriculumCard from 'sections/learning-management/learning-curriculums-subscribed/skeleton/EmptyCurriculumCard';
import { useDispatch, useSelector } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { fetchUserProgress, toInitialState } from 'store/reducers/userProgress';
import { curriculumTypeUserProgress, userProgressType } from 'types/userProgress';
// ==============================|| List ||============================== // // ==============================|| List ||============================== //
const allColumns = [
{
id: 1,
header: 'Default'
},
{
id: 2,
header: 'Title'
}
];
const List = () => { const List = () => {
const theme = useTheme();
const dispatch = useDispatch();
const { userProgress, error, success, isLoading } = useSelector(state => state.userProgress);
const { user } = useAuth();
const [data, setData] = useState<userProgressType["curriculums"]>([])
const matchDownSM = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
const [curriculumsData, setCurriculumsData] = useState<userProgressType["curriculums"]>([]);
const [sortBy, setSortBy] = useState('Default');
const [globalFilter, setGlobalFilter] = useState('');
const [page, setPage] = useState(1);
const handleChange = (event: SelectChangeEvent) => {
setSortBy(event.target.value as string);
};
// search
useEffect(() => {
if (!data || data.length == 0) return
const newData = data?.filter((value: any) => {
if (globalFilter) {
return value.curriculumTitle.toLowerCase().includes(globalFilter.toLowerCase());
} else {
return value;
}
});
setCurriculumsData(newData);
}, [globalFilter, data]);
const PER_PAGE = 6;
const count = Math.ceil(curriculumsData?.length! / PER_PAGE);
const _DATA = usePagination(curriculumsData, PER_PAGE);
const handleChangePage = (e: any, p: any) => {
setPage(p);
_DATA.jump(p);
};
const [expanded, setExpanded] = useState<string | false>('panel0');
const handleAccordionChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
setExpanded(newExpanded ? panel : false);
};
/**
* API Config
* User Progress API
*/
useEffect(() => {
if (!user) {
// User is missing
dispatch(
openSnackbar({
open: true,
message: 'User data is missing',
variant: 'alert',
alert: {
color: 'warning',
},
close: true,
})
);
} else if (!user.id) {
// User ID is missing
dispatch(
openSnackbar({
open: true,
message: 'User ID is missing',
variant: 'alert',
alert: {
color: 'warning',
},
close: true,
})
);
} else {
dispatch(fetchUserProgress(user.id));
}
}, [dispatch]);
useEffect(() => {
if (userProgress) {
setData(userProgress?.curriculums);
}
}, [userProgress])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return (
<>
<Box sx={{ position: 'relative', marginBottom: 3 }}>
<Stack direction="row" alignItems="center">
<Stack
direction={matchDownSM ? 'column' : 'row'}
sx={{ width: '100%' }}
spacing={1}
justifyContent="space-between"
alignItems="center"
>
{/* @ts-ignore */}
<GlobalFilter preGlobalFilteredRows={data} globalFilter={globalFilter} setGlobalFilter={setGlobalFilter} />
<Stack direction={matchDownSM ? 'column' : 'row'} alignItems="center" spacing={1}>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<Select
value={sortBy}
onChange={handleChange}
displayEmpty
inputProps={{ 'aria-label': 'Without label' }}
renderValue={(selected) => {
if (!selected) {
return <Typography variant="subtitle1">Sort By</Typography>;
}
return <Typography variant="subtitle2">Sort by ({sortBy})</Typography>;
}}
>
{allColumns.map((column) => {
return ( return (
<MainCard content={false}> <MenuItem key={column.id} value={column.header}>
<ScrollX> {column.header}
</ScrollX> </MenuItem>
</MainCard> );
})}
</Select>
</FormControl>
</Stack>
</Stack>
</Stack>
</Box>
<Grid container spacing={3}>
{curriculumsData?.length! > 0 ? (
_DATA
.currentData()
.sort(function (a: any, b: any) {
if (sortBy === 'Title') return a.curriculumTitle.localeCompare(b.curriculumTitle);
return a;
})
.map((curriculum: curriculumTypeUserProgress, index: number) => (
<Slide key={index} direction="up" in={true} timeout={50}>
<Grid item xs={12} sm={12} lg={12}>
<Box
sx={{
'& .MuiAccordion-root': {
borderColor: theme.palette.divider,
'& .MuiAccordionSummary-root': {
bgcolor: 'transparent',
flexDirection: 'row',
'&:focus-visible': {
bgcolor: 'primary.lighter'
}
},
'& .MuiAccordionDetails-root': {
borderColor: theme.palette.divider
},
'& .Mui-expanded': {
color: theme.palette.primary.main
}
}
}}
>
<Accordion expanded={expanded === `panel${index}`} onChange={handleAccordionChange(`panel${index}`)}>
<AccordionSummary aria-controls={`panel${index}d-content`} id={`panel${index}d-header`}>
<Stack direction="row" spacing={1.5} alignItems="center">
<BookOutlined style={{ fontSize: '26px' }} />
<Typography variant="h4">{curriculum.curriculumTitle}</Typography>
</Stack>
</AccordionSummary>
<AccordionDetails>
<CurriculumSection curriculum={curriculum} curriculumIndex={index} />
</AccordionDetails>
</Accordion>
</Box>
</Grid>
</Slide>
))
) : (
<EmptyCurriculumCard title={'System have no curriculumsData yet.'} />
)}
</Grid>
<Stack spacing={2} sx={{ p: 2.5 }} alignItems="flex-end">
<Pagination
count={count}
size="medium"
page={page}
showFirstButton
showLastButton
variant="combined"
color="primary"
onChange={handleChangePage}
/>
</Stack>
</>
) )
} }
......
import { useEffect, useRef, useState } from "react";
// material-ui
import { Alert, Box, Button, ButtonGroup, Dialog, DialogActions, DialogContent, DialogTitle, Divider, Grid, LinearProgress, List, ListItemAvatar, ListItemButton, ListItemSecondaryAction, ListItemText, Stack, Typography } from "@mui/material";
import { useTheme } from '@mui/material/styles';
// project import
import AntAvatar from 'components/@extended/Avatar';
import MainCard from "components/MainCard";
import UploadSingleFile from 'components/third-party/dropzone/SingleFile';
// types
import { tutorialTypeUserProgress } from "types/userProgress";
// assets
import { CheckCircleOutlined, CheckOutlined, ClockCircleOutlined, FileMarkdownFilled, LeftOutlined, PlayCircleOutlined, RightOutlined, TrophyOutlined, UserOutlined } from "@ant-design/icons";
import { PopupTransition } from "components/@extended/Transitions";
import ReportCard from "components/cards/statistics/ReportCard";
import { itemResultProps, selectedCommonDataProps, selectedItemContentProps } from "./types/types";
import CircularWithPath from "components/@extended/progress/CircularWithPath";
import useAuth from "hooks/useAuth";
import { useParams } from "react-router";
import Webcam from 'react-webcam';
import { useDispatch, useSelector } from "store";
import { CalculateMarks, toInitialState } from "store/reducers/marksCalculator";
import { openSnackbar } from "store/reducers/snackbar";
import { fetchUserProgress, updateUserProgress, toInitialState as userProgressToInitialState } from "store/reducers/userProgress";
// action style
const actionSX = {
mt: 0.75,
ml: 1,
top: 'auto',
right: 'auto',
alignSelf: 'flex-start',
transform: 'none'
};
function convertMinutesToHMS(minutes: number) {
const hours = Math.floor(minutes / 60);
const remainingMinutes = minutes % 60;
const seconds = Math.round((minutes % 1) * 60);
return `${hours} hr ${remainingMinutes} min ${seconds} sec`;
}
// ==============================|| Tutorial ||============================== //
const Tutorial = () => {
const theme = useTheme();
const dispatch = useDispatch();
const { marksCalculator, error, success, isLoading } = useSelector(state => state.marksCalculator);
const { userProgress, error: errorUserProgress, isLoading: isLoadingUserProgress, success: successUserProgress } = useSelector(state => state.userProgress);
const { curriculumIndex, tutorialIndex } = useParams();
const { user } = useAuth()
const [data, setData] = useState<tutorialTypeUserProgress>()
const [selectedItem, setSelectedItem] = useState<{ selectedCommonData: selectedCommonDataProps | null, backgroundColor: any | null }>({
selectedCommonData: null,
backgroundColor: 'white', // Initial background color
});
const [selectedItemContent, setSelectedItemContent] = useState<selectedItemContentProps | null>(null)
const [desc, setDesc] = useState("")
const [readMore, setReadMore] = useState(false)
const [itemDesc, setItemDesc] = useState("")
const [itemReadMore, setItemReadMore] = useState(false)
const [itemReferenceData, setItemReferenceData] = useState<"image" | "video">("image")
const [itemPracticeReferenceData, setItemPracticeReferenceData] = useState<"capture" | "upload">("capture")
const [itemResult, setItemResult] = useState<itemResultProps>({
itemMarkUser: 0,
status: "Pending"
})
useEffect(() => {
if (!curriculumIndex || !tutorialIndex) return
if (userProgress) {
const selectedTutorial = userProgress?.curriculums?.[parseInt(curriculumIndex)]?.tutorials?.[parseInt(tutorialIndex)];
if (selectedTutorial) {
setData(selectedTutorial);
}
}
}, [userProgress]);
const handleItemClick = (item: selectedCommonDataProps, backgroundColor: any) => {
setSelectedItem({
selectedCommonData: {
userId: item.userId,
curriculumCode: item.curriculumCode,
tutorialCode: item.tutorialCode,
title: item.title
},
backgroundColor,
});
};
useEffect(() => {
setDesc(data?.tutorialDescription?.slice(0, 200)!)
}, [data])
useEffect(() => {
if (!selectedItemContent?.description) return
setItemDesc(selectedItemContent?.description.slice(0, 200)!)
}, [selectedItemContent])
useEffect(() => {
// Filter data based on selectedItem.title
if (selectedItem && data) {
const filteredItem = data?.taskItems!.find((item) => item.title === selectedItem.selectedCommonData?.title);
setSelectedItemContent({
userId: selectedItem.selectedCommonData?.userId!,
curriculumCode: selectedItem.selectedCommonData?.curriculumCode!,
tutorialCode: selectedItem.selectedCommonData?.tutorialCode!,
...filteredItem!
} || null)
} else {
setSelectedItemContent(null);
}
}, [selectedItem]);
useEffect(() => {
setItemResult({
itemMarkUser: ((selectedItemContent?.taskItemMark! * parseInt(marksCalculator?.confidence!)) / 100)!,
status: marksCalculator?.status.toUpperCase()!
})
}, [marksCalculator])
//alert model
const [openModel, setOpenModel] = useState(false);
const [modelOpenFor, setModelOpenFor] = useState<"Practice" | "Complete">("Practice")
const handleModelClose = () => {
setOpenModel(!openModel);
};
const handleModelOpen = (modelFor: "Practice" | "Complete") => {
setModelOpenFor(modelFor)
setOpenModel(true);
};
// web cam
const webcamRef = useRef<Webcam>(null);
const [capturedImage, setCapturedImage] = useState<string | null>(null);
const capture = () => {
if (webcamRef.current) {
const imageSrc = webcamRef.current.getScreenshot();
setCapturedImage(imageSrc);
}
};
// upload image
const [uploadImage, setUploadImage] = useState<any>();
const TaskTrigger = (uploadImage: any, imgData: any, title: string) => {
if (itemPracticeReferenceData == "capture") {
if (typeof imgData === 'string' && imgData.trim() !== '') {
const curriculumIndex: number = 1;
const tutorialIndex: number = 1;
const imageData: any = imgData; // Your image data
let targetClass: string = ""; // Your target class
switch (title) {
case "Learn Number One":
targetClass = "One";
break;
case "Learn Number Two":
targetClass = "Two";
break;
case "Learn Number Three":
targetClass = "Three";
break;
case "Learn Number Four":
targetClass = "Four";
break;
case "Learn Number Five":
targetClass = "Five";
break;
case "Learn Number Six":
targetClass = "Six";
break;
case "Learn Number Seven":
targetClass = "Seven";
break;
case "Learn Number Eight":
targetClass = "Eight";
break;
case "Learn Number Nine":
targetClass = "Nine";
break;
case "Learn Number Ten":
targetClass = "Ten";
break;
default:
targetClass = "Initial";
break;
}
// Assuming imageData is a base64-encoded image
const base64Image = imageData; // Replace with your actual base64 data
const byteCharacters = atob(base64Image.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/jpeg' });
const file = new File([blob], 'image.jpg', { type: 'image/jpeg' });
dispatch(CalculateMarks(curriculumIndex, tutorialIndex, file, targetClass));
} else {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: "Invalid Image Data",
variant: 'alert',
alert: {
color: 'warning'
},
close: true
})
);
}
} else if (itemPracticeReferenceData == "upload") {
const curriculumIndex: number = 1;
const tutorialIndex: number = 1;
const imageData: any = uploadImage[0]; // Your image data
let targetClass: string = ""; // Your target class
switch (title) {
case "Learn Number One":
targetClass = "One";
break;
case "Learn Number Two":
targetClass = "Two";
break;
case "Learn Number Three":
targetClass = "Three";
break;
case "Learn Number Four":
targetClass = "Four";
break;
case "Learn Number Five":
targetClass = "Five";
break;
case "Learn Number Six":
targetClass = "Six";
break;
case "Learn Number Seven":
targetClass = "Seven";
break;
case "Learn Number Eight":
targetClass = "Eight";
break;
case "Learn Number Nine":
targetClass = "Nine";
break;
case "Learn Number Ten":
targetClass = "Ten";
break;
default:
targetClass = "Initial";
break;
}
dispatch(CalculateMarks(curriculumIndex, tutorialIndex, imageData, targetClass));
}
}
/**
* API Config
* Marks Calculator API
*/
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
if (modelOpenFor == "Complete") {
dispatch(updateUserProgress(
user?.id!,
userProgress?.curriculums?.[parseInt(curriculumIndex!)].curriculumCode!,
data?.tutorialCode!,
selectedItemContent?.title!,
((selectedItemContent?.taskItemMark! * parseInt(marksCalculator?.confidence!)) / 100)!,
0
))
}
dispatch(toInitialState())
}
}, [success])
// handel error
useEffect(() => {
if (errorUserProgress != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: errorUserProgress ? errorUserProgress.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(userProgressToInitialState())
}
}, [errorUserProgress])
// handel success
useEffect(() => {
if (successUserProgress != null) {
dispatch(
openSnackbar({
open: true,
message: successUserProgress,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(fetchUserProgress(user?.id!));
dispatch(userProgressToInitialState())
}
}, [successUserProgress])
return (
<>
<Grid container spacing={2}>
<Grid item md={12}>
<MainCard title="Overview">
<Grid container spacing={2}>
<Grid
item
xs={7}
sm={7}
sx={{}}
>
<Stack>
<Typography variant="h3" sx={{ mb: 2 }}>
{data?.tutorialTitle}
</Typography>
<Typography variant="h5" sx={{ textAlign: "justify" }}>
{desc}
<span style={{ fontWeight: "bold", cursor: "pointer" }}
onClick={() => {
if (!readMore) {
setDesc(data?.tutorialDescription!)
setReadMore(true)
} else {
setDesc(data?.tutorialDescription?.slice(0, 200)!)
setReadMore(false)
}
}} color="secondary">
{readMore ? "Show Less" : "...Read More"}
</span>
</Typography>
<Typography variant="h4" sx={{ pt: 3, pb: 1, zIndex: 1 }}>
{(data?.tutorialMarkUser! / data?.tutorialMarks!) * 100}% Completed
</Typography>
<Box sx={{ maxWidth: '60%' }}>
<LinearProgress variant="determinate" color="success" value={(data?.tutorialMarkUser! / data?.tutorialMarks!) * 100} />
</Box>
</Stack>
</Grid>
<Grid md={5} item>
<Grid container spacing={2}>
<Grid md={12} item>
<ReportCard
primary={`${data?.tutorialMarkUser?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
secondary="Tutorial User Mark" color={theme.palette.error.main} iconPrimary={FileMarkdownFilled} />
</Grid>
<Grid md={12} item>
<ReportCard primary={`${convertMinutesToHMS(data?.tutorialSpentTime!)}`} secondary="Tutorial Time Spent On" color={theme.palette.success.dark} iconPrimary={ClockCircleOutlined} />
</Grid>
</Grid>
</Grid>
</Grid>
</MainCard>
</Grid>
<Grid item md={4}>
<MainCard title="Task List">
<List
component="nav"
sx={{
py: 0,
'& .MuiListItemButton-root': {
'& .MuiListItemSecondaryAction-root': { ...actionSX, position: 'relative' }
}
}}
>
{data?.taskItems?.map((item, index) => {
const isSelected = selectedItem.selectedCommonData?.title === item.title;
const backgroundColor = isSelected ? theme.palette.primary.lighter : 'white';
const iconColor = isSelected ? 'warning' : 'success';
return (
<>
<ListItemButton
key={index}
divider
onClick={() => handleItemClick({
userId: "",
curriculumCode: "",
tutorialCode: data.tutorialCode!,
title: item.title
}, backgroundColor)}
sx={{ backgroundColor }}
>
<ListItemAvatar>
<AntAvatar alt="Basic" type="combined" color={iconColor}>
<ClockCircleOutlined />
</AntAvatar>
</ListItemAvatar>
<ListItemText primary={<Typography variant="subtitle1">{item.title}</Typography>} />
<ListItemSecondaryAction>
<Stack alignItems="flex-end">
<Typography variant="subtitle1" noWrap>User Mark : {item.taskItemMarkUser?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Typography>
<Typography variant="h6" color="secondary" noWrap> Mark : {item.taskItemMark?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})} </Typography>
</Stack>
</ListItemSecondaryAction>
</ListItemButton>
</>
)
})}
</List>
</MainCard>
</Grid>
<Grid item md={8}>
<MainCard title="Task View">
<Grid container spacing={2}>
{selectedItemContent !== null
?
<>
<Grid item md={8}>
<Typography variant="h4" sx={{ mb: 2 }}>
{selectedItemContent?.title}
</Typography>
<Typography variant="h5" sx={{ textAlign: "justify", mb: 2 }}>
{itemDesc}
<span style={{ fontWeight: "bold", cursor: "pointer" }}
onClick={() => {
if (!itemReadMore) {
setItemDesc(selectedItemContent?.description!)
setItemReadMore(true)
} else {
setItemDesc(selectedItemContent?.description?.slice(0, 200)!)
setItemReadMore(false)
}
}} color="secondary">
{itemReadMore ? "Show Less" : "...Read More"}
</span>
</Typography>
<MainCard title="How To Do">
<List
component="nav"
sx={{
py: 0,
'& .MuiListItemButton-root': {
'& .MuiListItemSecondaryAction-root': { ...actionSX, position: 'relative' }
}
}}
>
{selectedItemContent?.howToDo && selectedItemContent?.howToDo.map((i, index) => {
return (
<>
<ListItemButton divider>
<ListItemAvatar>
<AntAvatar alt="Basic" type="combined" color="info">
{index + 1}
</AntAvatar>
</ListItemAvatar>
<ListItemText primary={<Typography variant="subtitle1">{i}</Typography>} />
</ListItemButton>
</>
)
})}
</List>
</MainCard>
</Grid>
<Grid item xs={4}>
<Grid container spacing={2}>
<Grid item md={12}>
<ButtonGroup aria-label="outlined button group" sx={{ width: "100%" }}>
<Button fullWidth sx={{ width: "100%" }} size="small" variant={itemReferenceData == "image" ? "contained" : "outlined"} onClick={() => { setItemReferenceData("image") }}>Image Reference</Button>
<Button fullWidth sx={{ width: "100%" }} size="small" variant={itemReferenceData == "video" ? "contained" : "outlined"} onClick={() => { setItemReferenceData("video") }}>Vide Reference</Button>
</ButtonGroup>
</Grid>
<Grid item md={12} xs={4} sx={{ height: '246px', '& img': { mb: 0, width: '100%', height: '100%', objectFit: 'contain' } }}>
{itemReferenceData == "image" && <img src={selectedItemContent?.referenceImage} alt="feature" style={{ width: '100%', height: '100%' }} />}
{itemReferenceData == "video" && <>In Constriction ....</>}
</Grid>
</Grid>
</Grid>
<Grid item md={8}>
<Grid container spacing={2}>
<Grid item md={6}>
<ReportCard primary={`Task Mark : ${(selectedItemContent.taskItemMark)?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
secondary="Task Mark" color={theme.palette.success.dark} iconPrimary={CheckCircleOutlined}
/>
</Grid>
<Grid item md={6}>
<ReportCard primary={`User Mark : ${(selectedItemContent.taskItemMarkUser)?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
secondary="Task User Mark" color={theme.palette.success.dark} iconPrimary={UserOutlined}
/>
</Grid>
<Grid item md={12}>
<ReportCard
primary={`Pass Mark : ${(selectedItemContent?.taskItemMark! * (85 / 100))?.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
secondary="To Complete the task you should get 85% or higher of the task mark" color={theme.palette.success.dark} iconPrimary={TrophyOutlined}
/>
</Grid>
</Grid>
</Grid>
<Grid item md={4}>
<Grid container spacing={1}>
<Grid item md={12}>
<Button
variant="contained"
endIcon={<PlayCircleOutlined />}
fullWidth
sx={{ my: 1, width: "100%", height: "100%" }}
onClick={() => { handleModelOpen("Practice") }}
color="warning"
size="small"
>
Practice Task
</Button>
</Grid>
<Grid item md={12}>
<Button
variant="contained"
endIcon={<CheckOutlined />}
fullWidth
sx={{ my: 1, width: "100%", height: "100%" }}
onClick={() => { handleModelOpen("Complete") }}
color="success"
size="small"
>
Complete Task
</Button>
</Grid>
<Grid item md={6}>
<Button
variant="contained"
endIcon={<LeftOutlined />}
fullWidth
sx={{ my: 1, width: "100%", height: "100%" }}
onClick={() => { }}
color="secondary"
size="small"
>
Previous Task
</Button>
</Grid>
<Grid item md={6}>
<Button
variant="contained"
endIcon={<RightOutlined />}
fullWidth
sx={{ my: 1, width: "100%", height: "100%" }}
onClick={() => { }}
color={"info"}
size="small"
>
Next Task
</Button>
</Grid>
</Grid>
</Grid>
</>
:
<Grid item md={12}>
<Alert variant="border" color="warning">Select a Task</Alert>
</Grid>
}
</Grid>
</MainCard>
</Grid>
</Grid>
<Dialog
maxWidth="lg"
TransitionComponent={PopupTransition}
keepMounted
fullWidth
onClose={handleModelClose}
open={openModel}
sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }}
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle>{modelOpenFor} Item</DialogTitle>
<Divider />
<DialogContent sx={{ p: 2.5 }}>
<Grid container spacing={2}>
<Grid item md={8}>
<MainCard title="Capture / Upload Image">
<Grid container spacing={2}>
<Grid item md={12}>
<ButtonGroup aria-label="outlined button group" >
<Button fullWidth sx={{ whiteSpace: "nowrap" }} size="small" variant={itemPracticeReferenceData == "capture" ? "contained" : "outlined"} onClick={() => { setItemPracticeReferenceData("capture") }}>Capture Image</Button>
<Button fullWidth sx={{ whiteSpace: "nowrap" }} size="small" variant={itemPracticeReferenceData == "upload" ? "contained" : "outlined"} onClick={() => { setItemPracticeReferenceData("upload") }}>Upload Image</Button>
</ButtonGroup>
</Grid>
{itemPracticeReferenceData == "capture" && <>
<Grid item md={6}>
<Webcam
audio={false}
ref={webcamRef}
screenshotFormat="image/jpeg"
height={300}
width={400}
// videoConstraints={videoConstraints}
/>
</Grid>
<Grid item md={6}>
{capturedImage && (
<img src={capturedImage} alt="Captured" style={{ width: 400, height: 300 }} />
)}
</Grid>
</>}
{itemPracticeReferenceData == "upload" && <>
<Grid item md={12}>
<UploadSingleFile
file={uploadImage}
setFieldValue={function (field: string, value: any): void {
setUploadImage(value)
}}
/>
</Grid>
</>}
</Grid>
</MainCard>
</Grid>
<Grid item md={4}>
<MainCard title="Practice Result">
<Grid container spacing={2}>
<Grid item md={12}>
<ReportCard
primary={`Result : ${itemResult.itemMarkUser ? itemResult.itemMarkUser : "N/A"}`}
secondary="To Complete the task you should get 85% or higher of the task mark" color={theme.palette.success.dark} />
</Grid>
<Grid item md={12}>
<ReportCard
primary={`Status : ${itemResult.status ? itemResult.status : 'N/A'}`}
secondary="To Complete the task you should get 85% or higher of the task mark" color={theme.palette.success.dark} />
</Grid>
<Grid item md={12}>
<Button variant="contained" color="success" onClick={() => { TaskTrigger(uploadImage, webcamRef.current?.getScreenshot(), selectedItemContent?.title!) }} fullWidth disabled={isLoading && isLoadingUserProgress}>
{isLoading && isLoadingUserProgress ? <CircularWithPath /> : <>{modelOpenFor} Task</>}
</Button>
</Grid>
</Grid>
</MainCard>
</Grid>
<Grid item md={8}>
{itemPracticeReferenceData == "capture" && <Button size="small" variant="contained" onClick={capture} fullWidth>
Capture
</Button>
}
</Grid>
<Grid item md={4} />
</Grid>
</DialogContent>
<Divider />
<DialogActions sx={{ p: 2.5 }}>
<Grid container spacing={2}>
<Grid item md={12}>
<Button type="button" variant="contained" sx={{ float: "right" }} onClick={handleModelClose}>
Close
</Button>
</Grid>
</Grid>
</DialogActions>
</Dialog>
</>
)
}
export default Tutorial;
import { taskItemTypeUserProgress } from "types/userProgress";
export interface selectedItemContentProps extends taskItemTypeUserProgress {
userId: string
curriculumCode: string
tutorialCode: string
}
export interface selectedCommonDataProps {
userId: string
curriculumCode: string
tutorialCode: string
title: string
}
export interface itemResultProps {
itemMarkUser: number
status: string
}
\ No newline at end of file
...@@ -21,8 +21,11 @@ import { ...@@ -21,8 +21,11 @@ import {
import usePagination from 'hooks/usePagination'; import usePagination from 'hooks/usePagination';
import CurriculumCard from 'sections/learning-management/learning-curriculums/CurriculumCard'; import CurriculumCard from 'sections/learning-management/learning-curriculums/CurriculumCard';
import EmptyCurriculumCard from 'sections/learning-management/learning-curriculums/skeleton/EmptyCurriculumCard'; import EmptyCurriculumCard from 'sections/learning-management/learning-curriculums/skeleton/EmptyCurriculumCard';
import { useDispatch, useSelector } from 'store';
import { fetchCurriculums, toInitialState } from 'store/reducers/curriculum';
import { openSnackbar } from 'store/reducers/snackbar';
import { curriculumType } from 'types/curriculum';
import { GlobalFilter } from 'utils/react-table'; import { GlobalFilter } from 'utils/react-table';
import { dataProps } from './types/types';
// types // types
...@@ -37,64 +40,22 @@ const allColumns = [ ...@@ -37,64 +40,22 @@ const allColumns = [
}, },
{ {
id: 2, id: 2,
header: 'Code' header: 'Title'
},
{
id: 3,
header: 'Name'
},
{
id: 4,
header: 'Level'
},
{
id: 5,
header: 'Status'
} }
]; ];
const List = () => { const List = () => {
const data: dataProps[] = [ const dispatch = useDispatch();
{ const { curriculums, error, success, isLoading } = useSelector(state => state.curriculum);
"_id": "1", const { success: userProgressSuccess } = useSelector(state => state.userProgress);
"curriculumCode": "01",
"curriculumLevel": 1, const [data, setData] = useState<curriculumType[]>([])
"curriculumDescription": "This curriculum teaches basic sign language skills to help beginners communicate effectively using sign language.",
"curriculumName": "Learn Basic Sign Language Skills",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
"tutorials": [],
"status": 1,
"createdAt": new Date("2023-08-30T12:00:00Z"),
},
{
"_id": "2",
"curriculumCode": "02",
"curriculumLevel": 2,
"curriculumName": "Learn Intermediate Sign Language Skills",
"curriculumDescription": "This curriculum focuses on building intermediate sign language skills, allowing learners to engage in more complex conversations and interactions using sign language.",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
"tutorials": [],
"status": 1,
"createdAt": new Date("2023-08-30T12:00:00Z"),
},
{
"_id": "3",
"curriculumCode": "03",
"curriculumLevel": 3,
"curriculumName": "Learn Advance Sign Language Skills",
"curriculumDescription": "This curriculum is designed for those who already have a solid foundation in sign language. It covers advanced topics, nuances, and cultural aspects of sign language communication.",
"curriculumImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
"tutorials": [],
"status": 1,
"createdAt": new Date("2023-08-30T12:00:00Z"),
}
]
const matchDownSM = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm')); const matchDownSM = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
const [curriculumsData, setCurriculumsData] = useState<curriculumType[]>([]);
const [sortBy, setSortBy] = useState('Default'); const [sortBy, setSortBy] = useState('Default');
const [globalFilter, setGlobalFilter] = useState(''); const [globalFilter, setGlobalFilter] = useState('');
const [curriculumCard, setCurriculumCard] = useState<dataProps[]>([]);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const handleChange = (event: SelectChangeEvent) => { const handleChange = (event: SelectChangeEvent) => {
...@@ -105,27 +66,79 @@ const List = () => { ...@@ -105,27 +66,79 @@ const List = () => {
useEffect(() => { useEffect(() => {
const newData = data.filter((value: any) => { const newData = data.filter((value: any) => {
if (globalFilter) { if (globalFilter) {
return value.curriculumName.toLowerCase().includes(globalFilter.toLowerCase()); return value.curriculumTitle.toLowerCase().includes(globalFilter.toLowerCase());
} else { } else {
return value; return value;
} }
}); });
console.log(newData.length); setCurriculumsData(newData);
}, [globalFilter, data]);
setCurriculumCard(newData);
}, [globalFilter]);
const PER_PAGE = 6; const PER_PAGE = 6;
const count = Math.ceil(curriculumCard.length / PER_PAGE); const count = Math.ceil(curriculumsData.length / PER_PAGE);
const _DATA = usePagination(curriculumCard, PER_PAGE); const _DATA = usePagination(curriculumsData, PER_PAGE);
const handleChangePage = (e: any, p: any) => { const handleChangePage = (e: any, p: any) => {
setPage(p); setPage(p);
_DATA.jump(p); _DATA.jump(p);
}; };
/**
* API Config
* Curriculum API
*/
useEffect(() => {
dispatch(fetchCurriculums());
}, [dispatch, userProgressSuccess]);
useEffect(() => {
setData(curriculums);
}, [curriculums])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return ( return (
<> <>
<Box sx={{ position: 'relative', marginBottom: 3 }}> <Box sx={{ position: 'relative', marginBottom: 3 }}>
...@@ -168,19 +181,14 @@ const List = () => { ...@@ -168,19 +181,14 @@ const List = () => {
</Stack> </Stack>
</Box> </Box>
<Grid container spacing={3}> <Grid container spacing={3}>
{curriculumCard.length > 0 ? ( {curriculumsData.length > 0 ? (
_DATA _DATA
.currentData() .currentData()
.sort(function (a: any, b: any) { .sort(function (a: any, b: any) {
if (sortBy === 'Customer Name') return a.fatherName.localeCompare(b.fatherName); if (sortBy === 'Title') return a.curriculumTitle.localeCompare(b.curriculumTitle);
if (sortBy === 'Email') return a.email.localeCompare(b.email);
if (sortBy === 'Contact') return a.contact.localeCompare(b.contact);
if (sortBy === 'Age') return b.age < a.age ? 1 : -1;
if (sortBy === 'Country') return a.country.localeCompare(b.country);
if (sortBy === 'Status') return a.status.localeCompare(b.status);
return a; return a;
}) })
.map((curriculum: dataProps, index: number) => ( .map((curriculum: curriculumType, index: number) => (
<Slide key={index} direction="up" in={true} timeout={50}> <Slide key={index} direction="up" in={true} timeout={50}>
<Grid item xs={12} sm={6} lg={4}> <Grid item xs={12} sm={6} lg={4}>
<CurriculumCard curriculum={curriculum} /> <CurriculumCard curriculum={curriculum} />
...@@ -188,7 +196,7 @@ const List = () => { ...@@ -188,7 +196,7 @@ const List = () => {
</Slide> </Slide>
)) ))
) : ( ) : (
<EmptyCurriculumCard title={'System have no curriculums yet.'} /> <EmptyCurriculumCard title={'System have no curriculumsData yet.'} />
)} )}
</Grid> </Grid>
<Stack spacing={2} sx={{ p: 2.5 }} alignItems="flex-end"> <Stack spacing={2} sx={{ p: 2.5 }} alignItems="flex-end">
......
import { MouseEvent, useMemo } from 'react'; import { MouseEvent, useEffect, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
...@@ -31,7 +31,12 @@ import { ...@@ -31,7 +31,12 @@ import {
import { DeleteTwoTone, EditTwoTone } from '@ant-design/icons'; import { DeleteTwoTone, EditTwoTone } from '@ant-design/icons';
//types //types
import { ReactTableProps, dataProps } from './types/types'; import status from 'data/status';
import { useDispatch, useSelector } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { fetchUsers, toInitialState } from 'store/reducers/user';
import { Users } from 'types/user';
import { ReactTableProps } from './types/types';
// ==============================|| REACT TABLE ||============================== // // ==============================|| REACT TABLE ||============================== //
...@@ -101,10 +106,10 @@ function ReactTable({ columns, data }: ReactTableProps) { ...@@ -101,10 +106,10 @@ function ReactTable({ columns, data }: ReactTableProps) {
); );
}) })
) : ( ) : (
<EmptyTable msg="No Data" colSpan={5} /> <EmptyTable msg="No Data" colSpan={12} />
)} )}
<TableRow> <TableRow>
<TableCell sx={{ p: 2 }} colSpan={5}> <TableCell sx={{ p: 2 }} colSpan={12}>
<TablePagination gotoPage={gotoPage} rows={rows} setPageSize={setPageSize} pageIndex={pageIndex} pageSize={pageSize} /> <TablePagination gotoPage={gotoPage} rows={rows} setPageSize={setPageSize} pageIndex={pageIndex} pageSize={pageSize} />
</TableCell> </TableCell>
</TableRow> </TableRow>
...@@ -119,18 +124,22 @@ function ReactTable({ columns, data }: ReactTableProps) { ...@@ -119,18 +124,22 @@ function ReactTable({ columns, data }: ReactTableProps) {
const List = () => { const List = () => {
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch();
const { users, error, success, isLoading } = useSelector(state => state.user);
// table // table
const data: dataProps[] = [ // const data: dataProps[] = [
{ // {
id: 1, // id: 1,
userName: "Nuwan Gamage", // userName: "Nuwan Gamage",
userContactNumber: "0768523456", // userContactNumber: "0768523456",
userEmailAddress: "nuwangamage@gmail.com", // userEmailAddress: "nuwangamage@gmail.com",
userType: "Member", // userType: "Member",
userStatus: "Active" // userStatus: "Active"
} // }
] // ]
const [data, setData] = useState<Users[]>([])
const columns = useMemo( const columns = useMemo(
() => () =>
...@@ -155,28 +164,64 @@ const List = () => { ...@@ -155,28 +164,64 @@ const List = () => {
}, },
{ {
Header: 'User Name', Header: 'User Name',
accessor: 'userName', accessor: 'firstName',
className: 'cell-center', Cell: ({ row }: { row: Row }) => {
if (row.values.firstName === undefined || row.values.firstName === null || row.values.firstName === '') {
return <>-</>
}
if (typeof row.values.firstName === 'string') {
//@ts-ignore
return <>{row.values.firstName + " " + row.original.lastName}</>;
}
if (typeof row.values.firstName === 'number') {
return <>{row.values.firstName}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'User Email', Header: 'User Email',
accessor: 'userEmailAddress', accessor: 'email',
className: 'cell-center',
}, },
{ {
Header: 'User Contact Number', Header: 'User Contact Number',
accessor: 'userContactNumber', accessor: 'contactNumber',
className: 'cell-center',
}, },
{ {
Header: 'User Type', Header: 'User Type',
accessor: 'userType', accessor: 'type',
className: 'cell-center', Cell: ({ row }: { row: Row }) => {
if (row.values.type === undefined || row.values.type === null || row.values.type === '') {
return <>-</>
}
if (typeof row.values.type === 'string') {
return <>{row.values.type.toUpperCase()}</>;
}
if (typeof row.values.type === 'number') {
return <>{row.values.type}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'User Status', Header: 'User Status',
accessor: 'userStatus', accessor: 'states',
className: 'cell-center', className: 'cell-center',
Cell: ({ row }: { row: Row }) => {
if (row.values.states === undefined || row.values.states === null || row.values.states === '') {
return <>-</>
}
if (typeof row.values.states === 'string') {
return <>{status.find(status => status.id === parseInt(row.values.states))?.description || "-"}</>;
}
if (typeof row.values.states === 'number') {
return <>{status.find(status => status.id === row.values.states)?.description || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
id: "actions", id: "actions",
...@@ -225,6 +270,59 @@ const List = () => { ...@@ -225,6 +270,59 @@ const List = () => {
[] []
); );
/**
* API Config
* User API
*/
useEffect(() => {
dispatch(fetchUsers('member'));
}, [dispatch]);
useEffect(() => {
setData(users);
}, [users])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return ( return (
<> <>
<MainCard content={false}> <MainCard content={false}>
......
import { Column } from 'react-table'; import { Column } from 'react-table';
import { Users } from 'types/user';
export interface dataProps { export interface dataProps {
id: number | string | undefined id: number | string | undefined
...@@ -11,7 +12,7 @@ export interface dataProps { ...@@ -11,7 +12,7 @@ export interface dataProps {
export interface ReactTableProps { export interface ReactTableProps {
columns: Column[] columns: Column[]
data: dataProps[] data: Users[]
} }
export interface userProps { export interface userProps {
......
import { MouseEvent, useMemo, useState } from 'react'; import { MouseEvent, useEffect, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
...@@ -34,9 +34,15 @@ import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-desig ...@@ -34,9 +34,15 @@ import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-desig
//types //types
import { PopupTransition } from 'components/@extended/Transitions'; import { PopupTransition } from 'components/@extended/Transitions';
import curriculumLevels from 'data/curriculumLevels';
import status from 'data/status';
import AddEditCurriculum from 'sections/parameters/curriculum-management/AddEditCurriculum'; import AddEditCurriculum from 'sections/parameters/curriculum-management/AddEditCurriculum';
import AlertCurriculumDelete from 'sections/parameters/curriculum-management/AlertCurriculumDelete'; import AlertCurriculumDelete from 'sections/parameters/curriculum-management/AlertCurriculumDelete';
import { ReactTableProps, curriculumProps, dataProps } from './types/types'; import { useDispatch, useSelector } from 'store';
import { fetchCurriculums, toInitialState } from 'store/reducers/curriculum';
import { openSnackbar } from 'store/reducers/snackbar';
import { Curriculum, Curriculums } from 'types/curriculum';
import { ReactTableProps } from './types/types';
// ==============================|| REACT TABLE ||============================== // // ==============================|| REACT TABLE ||============================== //
...@@ -122,16 +128,21 @@ function ReactTable({ columns, data, handleAddEdit }: ReactTableProps) { ...@@ -122,16 +128,21 @@ function ReactTable({ columns, data, handleAddEdit }: ReactTableProps) {
// ==============================|| List ||============================== // // ==============================|| List ||============================== //
const List = () => { const List = () => {
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch();
const { curriculums, error, success, isLoading } = useSelector(state => state.curriculum);
// table // table
const data: dataProps[] = [] // const data: dataProps[] = []
// table
const [data, setData] = useState<Curriculums[]>([])
const columns = useMemo( const columns = useMemo(
() => () =>
[ [
{ {
Header: '#', Header: '#',
accessor: 'id', accessor: '_id',
className: 'cell-center', className: 'cell-center',
Cell: ({ row }: { row: Row }) => { Cell: ({ row }: { row: Row }) => {
if (row.id === undefined || row.id === null || row.id === '') { if (row.id === undefined || row.id === null || row.id === '') {
...@@ -153,19 +164,72 @@ const List = () => { ...@@ -153,19 +164,72 @@ const List = () => {
}, },
{ {
Header: 'Curriculum LVL', Header: 'Curriculum LVL',
accessor: 'curriculumLevel' accessor: 'curriculumLevel',
Cell: ({ row }: { row: Row }) => {
if (row.values.curriculumLevel === undefined || row.values.curriculumLevel === null || row.values.curriculumLevel === '') {
return <>-</>
}
if (typeof row.values.curriculumLevel === 'string') {
return <>{row.values.curriculumLevel}</>;
}
if (typeof row.values.curriculumLevel === 'number') {
return <>{curriculumLevels.find(curriculumLevel => curriculumLevel.id === row.values.curriculumLevel)?.description || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'Curriculum Name', Header: 'Curriculum Name',
accessor: 'curriculumTitle' accessor: 'curriculumTitle',
Cell: ({ row }: { row: Row }) => {
if (row.values.curriculumTitle === undefined || row.values.curriculumTitle === null || row.values.curriculumTitle === '') {
return <>-</>
}
if (typeof row.values.curriculumTitle === 'string') {
return <>{row.values.curriculumTitle}</>;
}
if (typeof row.values.curriculumTitle === 'number') {
return <>{row.values.curriculumTitle || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'Status', Header: 'Status',
accessor: 'status' accessor: 'status',
className: 'cell-center',
Cell: ({ row }: { row: Row }) => {
if (row.values.status === undefined || row.values.status === null || row.values.status === '') {
return <>-</>
}
if (typeof row.values.status === 'string') {
return <>{row.values.status}</>;
}
if (typeof row.values.status === 'number') {
return <>{status.find(status => status.id === row.values.status)?.description || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'Created By', Header: 'Created By',
accessor: 'createdBy' accessor: 'createdBy',
Cell: ({ row }: { row: Row }) => {
if (row.values.createdBy === undefined || row.values.createdBy === null || row.values.createdBy === '') {
return <>-</>
}
if (typeof row.values.createdBy === 'string') {
return <>{row.values.createdBy}</>;
}
if (typeof row.values.createdBy === 'number') {
return <>{row.values.createdBy}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
id: "actions", id: "actions",
...@@ -209,6 +273,7 @@ const List = () => { ...@@ -209,6 +273,7 @@ const List = () => {
onClick={(e: MouseEvent<HTMLButtonElement>) => { onClick={(e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); e.stopPropagation();
setCurriculumId(row.values._id) setCurriculumId(row.values._id)
setCurriculumTitle(row.values.curriculumTitle)
setOpenAlert(true) setOpenAlert(true)
}} }}
> >
...@@ -226,7 +291,7 @@ const List = () => { ...@@ -226,7 +291,7 @@ const List = () => {
//dialog model //dialog model
const [addEdit, setAddEdit] = useState<boolean>(false); const [addEdit, setAddEdit] = useState<boolean>(false);
const [curriculum, setCurriculum] = useState<curriculumProps>(); const [curriculum, setCurriculum] = useState<Curriculum>();
const handleAddEdit = () => { const handleAddEdit = () => {
setAddEdit(!addEdit); setAddEdit(!addEdit);
...@@ -235,12 +300,66 @@ const List = () => { ...@@ -235,12 +300,66 @@ const List = () => {
//alert model //alert model
const [openAlert, setOpenAlert] = useState(false); const [openAlert, setOpenAlert] = useState(false);
const [curriculumId, setCurriculumId] = useState<number | string | undefined>(undefined) const [curriculumId, setCurriculumId] = useState<string | undefined>(undefined)
const [curriculumTitle, setCurriculumTitle] = useState<string | undefined>(undefined)
const handleAlertClose = () => { const handleAlertClose = () => {
setOpenAlert(!openAlert); setOpenAlert(!openAlert);
}; };
/**
* API Config
* Curriculum API
*/
useEffect(() => {
dispatch(fetchCurriculums());
}, [dispatch]);
useEffect(() => {
setData(curriculums);
}, [curriculums])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return ( return (
<> <>
<MainCard content={false}> <MainCard content={false}>
...@@ -258,10 +377,10 @@ const List = () => { ...@@ -258,10 +377,10 @@ const List = () => {
sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }} sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }}
aria-describedby="alert-dialog-slide-description" aria-describedby="alert-dialog-slide-description"
> >
<AddEditCurriculum curriculum={curriculum} onCancel={handleAddEdit} /> <AddEditCurriculum curriculum={curriculum!} onCancel={handleAddEdit} />
</Dialog> </Dialog>
{/* alert model */} {/* alert model */}
{!curriculum && <AlertCurriculumDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={curriculumId} />} {!curriculum && <AlertCurriculumDelete title={curriculumTitle!} open={openAlert} handleClose={handleAlertClose} deleteId={curriculumId} />}
</MainCard> </MainCard>
</> </>
) )
......
import { Column } from 'react-table'; import { Column } from 'react-table';
import { Curriculums } from 'types/curriculum';
export interface dataProps { export interface dataProps {
_id: number | string | undefined; _id: number | string | undefined;
...@@ -17,7 +18,7 @@ export interface dataProps { ...@@ -17,7 +18,7 @@ export interface dataProps {
export interface ReactTableProps { export interface ReactTableProps {
columns: Column[] columns: Column[]
data: dataProps[] data: Curriculums[]
handleAddEdit: () => void handleAddEdit: () => void
} }
......
import { MouseEvent, useMemo, useState } from 'react'; import { MouseEvent, useEffect, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
...@@ -34,9 +34,14 @@ import { ...@@ -34,9 +34,14 @@ import {
import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons'; import { DeleteTwoTone, EditTwoTone, EyeTwoTone, PlusOutlined } from '@ant-design/icons';
//types //types
import status from 'data/status';
import AddEditTutorial from 'sections/parameters/tutorial-management/AddEditTutorial'; 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 { useDispatch, useSelector } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { fetchTutorials, toInitialState } from 'store/reducers/tutorial';
import { Tutorial, Tutorials } from 'types/tutorial';
import { ReactTableProps } from './types/types';
// ==============================|| REACT TABLE ||============================== // // ==============================|| REACT TABLE ||============================== //
...@@ -122,16 +127,158 @@ function ReactTable({ columns, data, handleAddEdit }: ReactTableProps) { ...@@ -122,16 +127,158 @@ function ReactTable({ columns, data, handleAddEdit }: ReactTableProps) {
// ==============================|| List ||============================== // // ==============================|| List ||============================== //
const List = () => { const List = () => {
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch();
const { tutorials, error, success, isLoading } = useSelector(state => state.tutorial);
// table
// const data: dataProps[] = [
// {
// "_id": "",
// "tutorialCode": "01",
// "tutorialTitle": "Numbers and Counting in Sign Language",
// "tutorialDescription": "In this tutorial, you'll discover how to express numbers visually using simple hand gestures. Each number has a unique sign that involves specific finger placements and hand movements. We'll break down each number step by step, providing you with clear instructions, images, and videos to help you learn effectively.",
// "tutorialImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
// "taskItems": [
// {
// "_id": "",
// "title": "Learn Number One",
// "description": "Learn how to sign the number one in sign language.",
// "howToDo": "- Extend your index finger straight up.\n- Keep the rest of your fingers closed.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_one.jpg",
// "referenceVideo": "https://example.com/number_one_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Two",
// "description": "Learn how to sign the number two in sign language.",
// "howToDo": "- Extend your index and middle fingers straight up.\n- Keep the rest of your fingers closed.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_two.jpg",
// "referenceVideo": "https://example.com/number_two_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Three",
// "description": "Learn how to sign the number three in sign language.",
// "howToDo": "- Extend your index, middle, and ring fingers straight up.\n- Keep the rest of your fingers closed.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_three.jpg",
// "referenceVideo": "https://example.com/number_three_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Four",
// "description": "Learn how to sign the number four in sign language.",
// "howToDo": "- Extend your thumb, index, middle, and ring fingers straight up.\n- Keep your pinky finger folded.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_four.jpg",
// "referenceVideo": "https://example.com/number_four_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Five",
// "description": "Learn how to sign the number five in sign language.",
// "howToDo": "- Extend all your fingers straight up.\n- Keep your thumb resting on the side of your palm.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_five.jpg",
// "referenceVideo": "https://example.com/number_five_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Six",
// "description": "Learn how to sign the number six in sign language.",
// "howToDo": "- Extend your thumb and pinky finger straight up.\n- Keep the rest of your fingers closed.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_six.jpg",
// "referenceVideo": "https://example.com/number_six_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Seven",
// "description": "Learn how to sign the number seven in sign language.",
// "howToDo": "- Extend your index, middle, and ring fingers straight up.\n- Keep your thumb, pinky, and pinky finger folded.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_seven.jpg",
// "referenceVideo": "https://example.com/number_seven_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Eight",
// "description": "Learn how to sign the number eight in sign language.",
// "howToDo": "- Extend all your fingers straight up.\n- Cross your index and middle fingers over your ring and pinky fingers.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_eight.jpg",
// "referenceVideo": "https://example.com/number_eight_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Nine",
// "description": "Learn how to sign the number nine in sign language.",
// "howToDo": "- Extend your thumb and all your fingers straight up.\n- Keep your pinky finger folded.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_nine.jpg",
// "referenceVideo": "https://example.com/number_nine_video.mp4",
// "taskItemMark": 10
// },
// {
// "_id": "",
// "title": "Learn Number Ten",
// "description": "Learn how to sign the number ten in sign language.",
// "howToDo": "- Extend your thumb, index, and middle fingers straight up.\n- Keep the rest of your fingers closed.\n- Hold your hand in front of your chest.",
// "referenceImage": "https://example.com/number_ten.jpg",
// "referenceVideo": "https://example.com/number_ten_video.mp4",
// "taskItemMark": 10
// }
// ],
// "status": 1,
// "createdAt": new Date("2023-08-30T12:00:00Z"),
// "createdBy": "Nuwan Gamage"
// },
// {
// "_id": "",
// "tutorialCode": "02",
// "tutorialTitle": "Everyday Vocabulary in Sign Language",
// "tutorialDescription": "Teach signs for everyday objects and activities, such as eat, drink, sleep, book, pen, etc.\nIntroduce signs for common words used in daily life.\nProvide visual demonstrations and interactive exercises for learners to practice using these signs.",
// "tutorialImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
// "taskItems": [],
// "status": 1,
// "createdAt": new Date("2023-08-30T12:00:00Z"),
// "createdBy": "Nuwan Gamage"
// },
// {
// "_id": "",
// "tutorialCode": "03",
// "tutorialTitle": "Family Signs in Sign Language",
// "tutorialDescription": "Teach signs for family members, such as mother, father, sister, brother, etc.\nIntroduce signs for common family-related words, such as family, love, and home.\nProvide visual demonstrations and practice exercises for learners to practice these family signs.",
// "tutorialImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
// "taskItems": [],
// "status": 1,
// "createdAt": new Date("2023-08-30T12:00:00Z"),
// "createdBy": "Nuwan Gamage"
// },
// {
// "_id": "",
// "tutorialCode": "04",
// "tutorialTitle": "Basic Conversational Phrases in Sign Language",
// "tutorialDescription": "Teach simple conversational phrases, such as \"What is your name?\" or \"How are you?\"\nIntroduce signs for common question words and phrases.\nProvide visual demonstrations and practice exercises for learners to practice these conversational phrases.",
// "tutorialImage": "https://drive.google.com/uc?export=view&id=1YACBlu7X-O7-DKv5DoW3AM9kgfT7Yhdc",
// "taskItems": [],
// "status": 1,
// "createdAt": new Date("2023-08-30T12:00:00Z"),
// "createdBy": "Nuwan Gamage"
// }
// ]
// table // table
const data: dataProps[] = [] const [data, setData] = useState<Tutorials[]>([])
const columns = useMemo( const columns = useMemo(
() => () =>
[ [
{ {
Header: '#', Header: '#',
accessor: 'id', accessor: '_id',
className: 'cell-center', className: 'cell-center',
Cell: ({ row }: { row: Row }) => { Cell: ({ row }: { row: Row }) => {
if (row.id === undefined || row.id === null || row.id === '') { if (row.id === undefined || row.id === null || row.id === '') {
...@@ -157,11 +304,38 @@ const List = () => { ...@@ -157,11 +304,38 @@ const List = () => {
}, },
{ {
Header: 'Status', Header: 'Status',
accessor: 'status' accessor: 'status',
className: 'cell-center',
Cell: ({ row }: { row: Row }) => {
if (row.values.status === undefined || row.values.status === null || row.values.status === '') {
return <>-</>
}
if (typeof row.values.status === 'string') {
return <>{row.values.status}</>;
}
if (typeof row.values.status === 'number') {
return <>{status.find(status => status.id === row.values.status)?.description || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'Created By', Header: 'Created By',
accessor: 'createdBy' accessor: 'createdBy',
Cell: ({ row }: { row: Row }) => {
if (row.values.createdBy === undefined || row.values.createdBy === null || row.values.createdBy === '') {
return <>-</>
}
if (typeof row.values.createdBy === 'string') {
return <>{row.values.createdBy}</>;
}
if (typeof row.values.createdBy === 'number') {
return <>{row.values.createdBy}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
id: "actions", id: "actions",
...@@ -204,6 +378,7 @@ const List = () => { ...@@ -204,6 +378,7 @@ const List = () => {
color="error" color="error"
onClick={(e: MouseEvent<HTMLButtonElement>) => { onClick={(e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation(); e.stopPropagation();
setTutorialTitle(row.values.tutorialTitle)
setTutorialId(row.values._id) setTutorialId(row.values._id)
setOpenAlert(true) setOpenAlert(true)
}} }}
...@@ -222,7 +397,7 @@ const List = () => { ...@@ -222,7 +397,7 @@ const List = () => {
//dialog model //dialog model
const [addEdit, setAddEdit] = useState<boolean>(false); const [addEdit, setAddEdit] = useState<boolean>(false);
const [tutorial, setTutorial] = useState<tutorialProps>(); const [tutorial, setTutorial] = useState<Tutorial>();
const handleAddEdit = () => { const handleAddEdit = () => {
setAddEdit(!addEdit); setAddEdit(!addEdit);
...@@ -231,12 +406,66 @@ const List = () => { ...@@ -231,12 +406,66 @@ const List = () => {
//alert model //alert model
const [openAlert, setOpenAlert] = useState(false); const [openAlert, setOpenAlert] = useState(false);
const [tutorialId, setTutorialId] = useState<number | string | undefined>(undefined) const [tutorialId, setTutorialId] = useState<string | undefined>(undefined)
const [tutorialTitle, setTutorialTitle] = useState<string | undefined>(undefined)
const handleAlertClose = () => { const handleAlertClose = () => {
setOpenAlert(!openAlert); setOpenAlert(!openAlert);
}; };
/**
* API Config
* Tutorial API
*/
useEffect(() => {
dispatch(fetchTutorials());
}, [dispatch]);
useEffect(() => {
setData(tutorials);
}, [tutorials])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return ( return (
<> <>
<MainCard content={false}> <MainCard content={false}>
...@@ -254,10 +483,10 @@ const List = () => { ...@@ -254,10 +483,10 @@ const List = () => {
sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }} sx={{ '& .MuiDialog-paper': { p: 0 }, transition: 'transform 225ms' }}
aria-describedby="alert-dialog-slide-description" aria-describedby="alert-dialog-slide-description"
> >
<AddEditTutorial tutorial={tutorial} onCancel={handleAddEdit} /> <AddEditTutorial tutorial={tutorial!} onCancel={handleAddEdit} />
</Dialog> </Dialog>
{/* alert model */} {/* alert model */}
{!tutorial && <AlertTutorialDelete title={""} open={openAlert} handleClose={handleAlertClose} deleteId={tutorialId} />} {!tutorial && <AlertTutorialDelete title={tutorialTitle!} open={openAlert} handleClose={handleAlertClose} deleteId={tutorialId} />}
</MainCard> </MainCard>
</> </>
) )
......
import { Column } from 'react-table'; import { Column } from 'react-table';
import { Tutorials } from 'types/tutorial';
export interface dataProps { export interface dataProps {
_id: number | string | undefined; _id: number | string | undefined;
...@@ -6,17 +7,17 @@ export interface dataProps { ...@@ -6,17 +7,17 @@ export interface dataProps {
tutorialTitle: string; tutorialTitle: string;
tutorialDescription: string; tutorialDescription: string;
tutorialImage: string; tutorialImage: string;
status: number; status?: number;
createdBy: string; createdBy?: string;
updatedBy: string; updatedBy?: string;
createdAt: Date; createdAt?: Date;
updatedAt: Date; updatedAt?: Date;
taskItems: taskItemProps[] taskItems: taskItemProps[]
} }
export interface ReactTableProps { export interface ReactTableProps {
columns: Column[] columns: Column[]
data: dataProps[] data: Tutorials[]
handleAddEdit: () => void handleAddEdit: () => void
} }
...@@ -41,4 +42,5 @@ export interface taskItemProps { ...@@ -41,4 +42,5 @@ export interface taskItemProps {
howToDo: string; howToDo: string;
referenceImage: string; referenceImage: string;
referenceVideo: string; referenceVideo: string;
taskItemMark: number;
} }
\ No newline at end of file
import axios from 'axios';
class SignLanguageToTextService {
predictSignLanguageVideo(speed, data) {
return axios.post(
`http://127.0.0.1:8000/predict-sign-language/video/speed_levels?speed=${speed}`,
data
);
}
}
export default new SignLanguageToTextService();
import axios from 'axios';
class VideoToSignLanguage {
videoTranslation(data) {
return axios.post(
// @ts-ignore
`http://127.0.0.1:8000/translated_items/`,
data
);
}
}
export default new VideoToSignLanguage();
...@@ -154,7 +154,7 @@ const Process = () => { ...@@ -154,7 +154,7 @@ const Process = () => {
}; };
return ( return (
<> <>
<MainCard content={false}> <MainCard content={false} title="Translate Sinhala Sign Language into Text Here">
<ScrollX> <ScrollX>
{/* content here */} {/* content here */}
...@@ -233,7 +233,7 @@ const Process = () => { ...@@ -233,7 +233,7 @@ const Process = () => {
step={10} step={10}
marks marks
min={10} min={10}
max={110} max={100}
/> />
<h4>Speed - {speed}</h4> <h4>Speed - {speed}</h4>
</Grid> </Grid>
...@@ -331,7 +331,7 @@ const Process = () => { ...@@ -331,7 +331,7 @@ const Process = () => {
step={10} step={10}
marks marks
min={10} min={10}
max={110} max={100}
/> />
<h4>Speed - {speed}</h4> <h4>Speed - {speed}</h4>
</Grid> </Grid>
......
import { MouseEvent, useMemo, useState } from 'react'; import { MouseEvent, useEffect, useMemo, useState } from 'react';
// material-ui // material-ui
import { import {
...@@ -32,11 +32,16 @@ import { ...@@ -32,11 +32,16 @@ import {
import { DeleteTwoTone, EditTwoTone, PlusOutlined } from '@ant-design/icons'; import { DeleteTwoTone, EditTwoTone, PlusOutlined } from '@ant-design/icons';
//types //types
import { ReactTableProps, dataProps, userProps } from './types/types'; import status from 'data/status';
import { useDispatch, useSelector } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { fetchUsersByType, toInitialState } from 'store/reducers/user';
import { Users } from 'types/user';
import { ReactTableProps, userProps } from './types/types';
// ==============================|| REACT TABLE ||============================== // // ==============================|| REACT TABLE ||============================== //
function ReactTable({ columns, data , handleAddEdit}: ReactTableProps) { function ReactTable({ columns, data, handleAddEdit }: ReactTableProps) {
const filterTypes = useMemo(() => renderFilterTypes, []); const filterTypes = useMemo(() => renderFilterTypes, []);
const defaultColumn = useMemo(() => ({ Filter: DefaultColumnFilter }), []); const defaultColumn = useMemo(() => ({ Filter: DefaultColumnFilter }), []);
...@@ -102,10 +107,10 @@ function ReactTable({ columns, data , handleAddEdit}: ReactTableProps) { ...@@ -102,10 +107,10 @@ function ReactTable({ columns, data , handleAddEdit}: ReactTableProps) {
); );
}) })
) : ( ) : (
<EmptyTable msg="No Data" colSpan={5} /> <EmptyTable msg="No Data" colSpan={12} />
)} )}
<TableRow> <TableRow>
<TableCell sx={{ p: 2 }} colSpan={5}> <TableCell sx={{ p: 2 }} colSpan={12}>
<TablePagination gotoPage={gotoPage} rows={rows} setPageSize={setPageSize} pageIndex={pageIndex} pageSize={pageSize} /> <TablePagination gotoPage={gotoPage} rows={rows} setPageSize={setPageSize} pageIndex={pageIndex} pageSize={pageSize} />
</TableCell> </TableCell>
</TableRow> </TableRow>
...@@ -120,26 +125,33 @@ function ReactTable({ columns, data , handleAddEdit}: ReactTableProps) { ...@@ -120,26 +125,33 @@ function ReactTable({ columns, data , handleAddEdit}: ReactTableProps) {
const List = () => { const List = () => {
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch();
const { users, error, success, isLoading } = useSelector(state => state.user);
// table
// const data: dataProps[] = [
// {
// id: 1,
// userName: "Janith Gamage",
// userContactNumber: "0768523525",
// userEmailAddress: "janithgamage1.ed@gmail.com",
// userType: "Admin",
// userStatus: "Active"
// },
// {
// id: 1,
// userName: "Nuwan Gamage",
// userContactNumber: "0768523456",
// userEmailAddress: "nuwangamage@gmail.com",
// userType: "Member",
// userStatus: "Active"
// }
// ]
// table // table
const data: dataProps[] = [
{ const [data, setData] = useState<Users[]>([])
id: 1,
userName: "Janith Gamage",
userContactNumber: "0768523525",
userEmailAddress: "janithgamage1.ed@gmail.com",
userType: "Admin",
userStatus: "Active"
},
{
id: 1,
userName: "Nuwan Gamage",
userContactNumber: "0768523456",
userEmailAddress: "nuwangamage@gmail.com",
userType: "Member",
userStatus: "Active"
}
]
//dialog model //dialog model
const [addEdit, setAddEdit] = useState<boolean>(false); const [addEdit, setAddEdit] = useState<boolean>(false);
...@@ -173,28 +185,64 @@ const List = () => { ...@@ -173,28 +185,64 @@ const List = () => {
}, },
{ {
Header: 'User Name', Header: 'User Name',
accessor: 'userName', accessor: 'firstName',
className: 'cell-center', Cell: ({ row }: { row: Row }) => {
if (row.values.firstName === undefined || row.values.firstName === null || row.values.firstName === '') {
return <>-</>
}
if (typeof row.values.firstName === 'string') {
//@ts-ignore
return <>{row.values.firstName + " " + row.original.lastName}</>;
}
if (typeof row.values.firstName === 'number') {
return <>{row.values.firstName}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'User Email', Header: 'User Email',
accessor: 'userEmailAddress', accessor: 'email',
className: 'cell-center',
}, },
{ {
Header: 'User Contact Number', Header: 'User Contact Number',
accessor: 'userContactNumber', accessor: 'contactNumber',
className: 'cell-center',
}, },
{ {
Header: 'User Type', Header: 'User Type',
accessor: 'userType', accessor: 'type',
className: 'cell-center', Cell: ({ row }: { row: Row }) => {
if (row.values.type === undefined || row.values.type === null || row.values.type === '') {
return <>-</>
}
if (typeof row.values.type === 'string') {
return <>{row.values.type.toUpperCase()}</>;
}
if (typeof row.values.type === 'number') {
return <>{row.values.type}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
Header: 'User Status', Header: 'User Status',
accessor: 'userStatus', accessor: 'states',
className: 'cell-center', className: 'cell-center',
Cell: ({ row }: { row: Row }) => {
if (row.values.states === undefined || row.values.states === null || row.values.states === '') {
return <>-</>
}
if (typeof row.values.states === 'string') {
return <>{status.find(status => status.id === parseInt(row.values.states))?.description || "-"}</>;
}
if (typeof row.values.states === 'number') {
return <>{status.find(status => status.id === row.values.states)?.description || "-"}</>;
}
// Handle any other data types if necessary
return <>-</>;
}
}, },
{ {
id: "actions", id: "actions",
...@@ -243,6 +291,59 @@ const List = () => { ...@@ -243,6 +291,59 @@ const List = () => {
[] []
); );
/**
* API Config
* User API
*/
useEffect(() => {
dispatch(fetchUsersByType());
}, [dispatch]);
useEffect(() => {
setData(users);
}, [users])
// handel error
useEffect(() => {
if (error != null) {
dispatch(
openSnackbar({
open: true,
//@ts-ignore
message: error ? error.Message : "Something went wrong ...",
variant: 'alert',
alert: {
color: 'error'
},
close: true
})
);
dispatch(toInitialState())
}
}, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
if (isLoading) {
return <div>Loading...</div>;
}
return ( return (
<> <>
<MainCard content={false}> <MainCard content={false}>
......
import { Column } from 'react-table'; import { Column } from 'react-table';
import { Users } from 'types/user';
export interface dataProps { export interface dataProps {
id: number | string | undefined id: number | string | undefined
...@@ -11,7 +12,7 @@ export interface dataProps { ...@@ -11,7 +12,7 @@ export interface dataProps {
export interface ReactTableProps { export interface ReactTableProps {
columns: Column[] columns: Column[]
data: dataProps[] data: Users[]
handleAddEdit: () => void handleAddEdit: () => void
} }
......
// project import
import {
Box,
Button,
ButtonGroup,
Card,
CardContent,
CardHeader,
Container,
Grid,
IconButton,
InputAdornment,
LinearProgress,
Paper,
// Slider,
Stack,
TextField,
Typography
} from '@mui/material';
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
import { CloudUploadOutlined, CopyOutlined, HighlightOutlined, TranslationOutlined } from '@ant-design/icons';
import axios from 'axios';
import { MuiFileInput } from 'mui-file-input';
import { useSnackbar } from 'notistack';
import React, { useState } from 'react';
// import Unity, { UnityContext } from "react-unity-webgl";
// ---------- * Unity Application * ------------------------------
// const unityContext = new UnityContext ({
// loaderUrl: "build/myunityapp.loader.js",
// dataUrl: "build/myunityapp.data",
// frameworkUrl: "build/myunityapp.framework.js",
// codeUrl: "build/myunityapp.wasm",
// });
// ==============================|| List ||============================== //
const VideoTranslate = () => {
const [file, setFile] = useState<File | string | null>(null);
const [videoUrl, setVideoUrl] = useState('');
const [loading, setLoading] = useState(false);
const [value, setValue] = useState('');
const [translatedTextSi, setTranslatedTextSi] = useState('');
const [translatedTextEn, setTranslatedTextEn] = useState('');
const [showUnityWebGL, setShowUnityWebGL] = useState(false);
const handleDropSingleFile = (files: any) => {
if (files) {
setFile(
Object.assign(files, {
preview: URL.createObjectURL(files)
})
);
setVideoUrl(URL.createObjectURL(files));
}
};
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setValue(event.target.value);
};
// ----------------- Video Upload ------------------------------------------------
// const TranslateVideoToSignLanguage = async () => {
// if (file) {
// setLoading(true);
// const formData = new FormData();
// //@ts-ignore
// formData.append('video', file, file.name);
// try {
// const response = await VideoToSignLanguageService.videoTranslation(formData);
// const { translated_text_si, translated_text_en } = response.data;
// setTranslatedTextSi(translated_text_si);
// setTranslatedTextEn(translated_text_en);
// if (response.status == 200) {
// console.log(response.data);
// // setValue(response.data.predictions);
// } else {
// enqueueSnackbar('Something went Wrong!', { variant: 'error' });
// }
// // setLoading(false);
// } catch (error) {
// console.log(error);
// setLoading(false);
// enqueueSnackbar('Something went Wrong!', { variant: 'error' });
// }
// } else {
// enqueueSnackbar('Please select a file.', { variant: 'warning' });
// }
// };
async function uploadVideo() {
setLoading(true)
if (file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await axios.post('http://127.0.0.1:8000/rest_pyton/uploaded_video', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
setTranslatedTextEn(response.data.translated_text_en)
setTranslatedTextSi(response.data.translated_text_si)
// Show the Unity WebGL build
setShowUnityWebGL(true);
setLoading(false)
} catch (error) {
console.error('Error:', error);
setLoading(false)
}
} else {
console.error('No file selected.');
setLoading(false)
}
}
const { enqueueSnackbar } = useSnackbar();
const onCopy = (text: string) => {
if (text) {
navigator.clipboard.writeText(text);
enqueueSnackbar('Copied!', { variant: 'success' });
}
};
return (
<MainCard content={false}>
<ScrollX>
{/* Content Here */}
<Container
sx={{
padding: 3,
bgcolor: '#625D5D',
color: '#fafafb',
borderRadius: 6,
// boxShadow: '0px 4px 6px rgba(0, 0, 0, 0.1)' // Subtle box shadow
}}
>
{/* Double Button Here */}
<ButtonGroup
disableElevation
variant="contained"
aria-label="Customized buttons"
sx={{
marginBottom: '20px',
backgroundColor: '#ff3c3c', // Change background color
'& .MuiButton-root': { // Apply styles to individual buttons
color: 'white', // Text color
'&:hover': {
backgroundColor: '#000000' // Change color on hover
}
}
}}
>
<Button
sx={{
bgcolor: '#ff3c3c',
padding: '10px 50px',
fontSize: '1.05rem', // Larger font size
'& .anticon': {
fontSize: '1.2rem', // Larger icon size
},
}}
// variant={checkTranalationTypeForUpload()}
startIcon={<CloudUploadOutlined />}
// onClick={() => {
// setIsUploadFile(true);
// }}
>
Upload
</Button>
<Button
sx={{
bgcolor: '#ff3c3c',
padding: '10px 50px',
fontSize: '1.05rem', // Larger font size
'& .anticon': {
fontSize: '1.2rem', // Larger icon size
},
}}
// variant={checkTranalationTypeForRecord()}
startIcon={<HighlightOutlined />}
// onClick={() => {
// setIsUploadFile(false);
// }}
>
Text
</Button>
</ButtonGroup>
{/* Video uploading */}
<Box sx={{ flexGrow: 1 }}>
<Card>
<CardHeader title="Upload a video | Drag & Drop or Select File" />
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<Card sx={{ marginBottom: '20px', marginLeft: '10px', padding: '35px 10px' }}>
<CardContent>
{/* ! Important */}
{/* @ts-ignore */}
<MuiFileInput value={file} onChange={handleDropSingleFile} inputProps={{ accept: 'video/*' }} />
<Paper style={{ padding: '20px', marginTop: '15px' }}>
<Typography variant="h5" align="center" gutterBottom>
Preview
</Typography>
<div style={{ marginTop: '20px', textAlign: 'center' }}>
{file ? <video src={videoUrl} width="400" controls /> : <p>No Video Selected ...</p>}
</div>
</Paper>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={6}>
<Card sx={{ p: 7, minHeight: 300, marginBottom: '10px', marginRight: '10px' }}>
<Box display="grid" gap={5}>
<Stack spacing={2}>
<Grid container spacing={1}>
{/* <Grid item xs={12} md={6}> */}
{/* <h3>Set Sign Speed </h3> */}
{/* <Slider
defaultValue={30}
getAriaValueText={valuetext}
valueLabelDisplay="auto"
step={10}
marks
min={10}
max={110}
/> */}
{/* <h4>Speed - {speed}</h4> */}
{/* </Grid> */}
<Grid item xs={12} md={6} container direction="row" justifyContent="flex-start" alignItems="center">
<Button
variant="contained"
style={{ width: '200px', height: '60px', fontSize: '20px' }}
sx={{
mb: 3
}}
disabled={loading}
onClick={uploadVideo}
endIcon={<TranslationOutlined />}
>
Translate
</Button>
{/* ... other JSX ... */}
{/* Conditionally render the Unity WebGL build */}
{showUnityWebGL && (
<iframe
src="https://64f66d39fdef493229b2ddd9--lambent-unicorn-97396a.netlify.app/"
width="700px"
height="700px" // Adjust the height as needed
title="Unity WebGL"
style={{ border: 'none', overflow: 'hidden' }}
></iframe>
)}
{/* ... other JSX ... */}
{/* -------- Translated Sinhala Unicode ------------------------- */}
<Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic', marginBottom: 2 }}>
Sinhala Unicode
</Typography>
<TextField
sx={{
marginBottom: 2
}}
fullWidth
value={translatedTextSi}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/>
{/* -------- Translated English Unicode ------------------------- */}
<Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic' }}>
English Unicode
</Typography>
<TextField
fullWidth
value={translatedTextEn}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/>
{/* ----------------------------- */}
</Grid>
</Grid>
{loading ? (
<Card>
<CardContent>
<LinearProgress />
<center>
<Typography variant="h5" component="div" sx={{ marginTop: 2 }}>
Loading...
</Typography>
</center>
</CardContent>
</Card>
) : (
<div>
{/* -------- Translated Sinhala Unicode ------------------------- */}
{/* <Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic', marginBottom: 2 }}>
Sinhala Unicode
</Typography>
<TextField
sx={{
marginBottom: 2
}}
fullWidth
value={translatedTextSi}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/> */}
{/* -------- Translated English Unicode ------------------------- */}
{/* <Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic' }}>
English Unicode
</Typography>
<TextField
fullWidth
value={translatedTextEn}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/> */}
</div>
)}
</Stack>
</Box>
</Card>
</Grid>
</Grid>
</Card>
</Box>
</Container>
</ScrollX>
</MainCard>
);
};
export default VideoTranslate;
\ No newline at end of file
// project import
import {
Box,
Button,
ButtonGroup,
Card,
CardContent,
CardHeader,
Container,
Grid,
IconButton,
InputAdornment,
LinearProgress,
Paper,
// Slider,
Stack,
TextField,
Typography
} from '@mui/material';
import MainCard from 'components/MainCard';
import ScrollX from 'components/ScrollX';
import { CloudUploadOutlined, CopyOutlined, HighlightOutlined, TranslationOutlined } from '@ant-design/icons';
import axios from 'axios';
import { MuiFileInput } from 'mui-file-input';
import { useSnackbar } from 'notistack';
import { useState } from 'react';
// ==============================|| List ||============================== //
const VideoTranslate = () => {
const [file, setFile] = useState<File | string | null>(null);
const [videoUrl, setVideoUrl] = useState('');
const [loading, setLoading] = useState(false);
const [value, setValue] = useState('');
const [translatedTextSi, setTranslatedTextSi] = useState('');
const [translatedTextEn, setTranslatedTextEn] = useState('');
const handleDropSingleFile = (files: any) => {
if (files) {
setFile(
Object.assign(files, {
preview: URL.createObjectURL(files)
})
);
setVideoUrl(URL.createObjectURL(files));
}
};
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setValue(event.target.value);
};
// ----------------- Video Upload ------------------------------------------------
// const TranslateVideoToSignLanguage = async () => {
// if (file) {
// setLoading(true);
// const formData = new FormData();
// //@ts-ignore
// formData.append('video', file, file.name);
// try {
// const response = await VideoToSignLanguageService.videoTranslation(formData);
// const { translated_text_si, translated_text_en } = response.data;
// setTranslatedTextSi(translated_text_si);
// setTranslatedTextEn(translated_text_en);
// if (response.status == 200) {
// console.log(response.data);
// // setValue(response.data.predictions);
// } else {
// enqueueSnackbar('Something went Wrong!', { variant: 'error' });
// }
// // setLoading(false);
// } catch (error) {
// console.log(error);
// setLoading(false);
// enqueueSnackbar('Something went Wrong!', { variant: 'error' });
// }
// } else {
// enqueueSnackbar('Please select a file.', { variant: 'warning' });
// }
// };
async function uploadVideo() {
setLoading(true)
if (file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await axios.post('http://127.0.0.1:8000/rest_pyton/uploaded_video', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
setTranslatedTextEn(response.data.translated_text_en)
setTranslatedTextSi(response.data.translated_text_si)
setLoading(false)
} catch (error) {
console.error('Error:', error);
setLoading(false)
}
} else {
console.error('No file selected.');
setLoading(false)
}
}
const { enqueueSnackbar } = useSnackbar();
const onCopy = (text: string) => {
if (text) {
navigator.clipboard.writeText(text);
enqueueSnackbar('Copied!', { variant: 'success' });
}
};
return (
<MainCard content={false}>
<ScrollX>
{/* Content Here */}
<Container
sx={{
padding: 3,
bgcolor: '#625D5D',
color: '#fafafb',
borderRadius: 6,
// boxShadow: '0px 4px 6px rgba(0, 0, 0, 0.1)' // Subtle box shadow
}}
>
{/* Double Button Here */}
<ButtonGroup
disableElevation
variant="contained"
aria-label="Customized buttons"
sx={{
marginBottom: '20px',
backgroundColor: '#ff3c3c', // Change background color
'& .MuiButton-root': { // Apply styles to individual buttons
color: 'white', // Text color
'&:hover': {
backgroundColor: '#000000' // Change color on hover
}
}
}}
>
<Button
sx={{
bgcolor: '#ff3c3c',
padding: '10px 50px',
fontSize: '1.05rem', // Larger font size
'& .anticon': {
fontSize: '1.2rem', // Larger icon size
},
}}
// variant={checkTranalationTypeForUpload()}
startIcon={<CloudUploadOutlined />}
// onClick={() => {
// setIsUploadFile(true);
// }}
>
Upload
</Button>
<Button
sx={{
bgcolor: '#ff3c3c',
padding: '10px 50px',
fontSize: '1.05rem', // Larger font size
'& .anticon': {
fontSize: '1.2rem', // Larger icon size
},
}}
// variant={checkTranalationTypeForRecord()}
startIcon={<HighlightOutlined />}
// onClick={() => {
// setIsUploadFile(false);
// }}
>
Text
</Button>
</ButtonGroup>
{/* Video uploading */}
<Box sx={{ flexGrow: 1 }}>
<Card>
<CardHeader title="Upload a video | Drag & Drop or Select File" />
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<Card sx={{ marginBottom: '20px', marginLeft: '10px', padding: '35px 10px' }}>
<CardContent>
{/* ! Important */}
{/* @ts-ignore */}
<MuiFileInput value={file} onChange={handleDropSingleFile} inputProps={{ accept: 'video/*' }} />
<Paper style={{ padding: '20px', marginTop: '15px' }}>
<Typography variant="h5" align="center" gutterBottom>
Preview
</Typography>
<div style={{ marginTop: '20px', textAlign: 'center' }}>
{file ? <video src={videoUrl} width="400" controls /> : <p>No Video Selected ...</p>}
</div>
</Paper>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={6}>
<Card sx={{ p: 5, minHeight: 300, marginBottom: '10px', marginRight: '10px' }}>
<Box display="grid" gap={5}>
<Stack spacing={2}>
<Grid container spacing={1}>
{/* <Grid item xs={12} md={6}> */}
{/* <h3>Set Sign Speed </h3> */}
{/* <Slider
defaultValue={30}
getAriaValueText={valuetext}
valueLabelDisplay="auto"
step={10}
marks
min={10}
max={110}
/> */}
{/* <h4>Speed - {speed}</h4> */}
{/* </Grid> */}
<Grid item xs={12} md={6} container direction="row" justifyContent="flex-start" alignItems="center">
<Button
variant="contained"
style={{ width: '200px', height: '60px', fontSize: '20px' }}
sx={{
mb: 3
}}
disabled={loading}
onClick={uploadVideo}
endIcon={<TranslationOutlined />}
>
Translate
</Button>
</Grid>
</Grid>
{loading ? (
<Card>
<CardContent>
<LinearProgress />
<center>
<Typography variant="h5" component="div" sx={{ marginTop: 2 }}>
Loading...
</Typography>
</center>
</CardContent>
</Card>
) : (
<div>
{/* -------- Translated Avatar ------------------------- */}
<Typography variant="overline" sx={{ color: 'text.secondary', marginBottom: 2 }}>
Translated Avatar
</Typography>
<Paper elevation={3} sx={{ p: 2, maxWidth: 600, margin: '0 auto', marginBottom: 3 }}>
<video controls width="100%" height="auto">
{/* <source src="your-video-url.mp4" type="video/mp4" /> */}
Your browser does not support the video tag.
</video>
</Paper>
{/* -------- Translated Sinhala Unicode ------------------------- */}
<Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic', marginBottom: 2 }}>
Sinhala Unicode
</Typography>
<TextField
sx={{
marginBottom: 2
}}
fullWidth
value={translatedTextSi}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/>
{/* -------- Translated English Unicode ------------------------- */}
<Typography variant="overline" sx={{ color: 'text.secondary', fontStyle: 'italic' }}>
English Unicode
</Typography>
<TextField
fullWidth
value={translatedTextEn}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => onCopy(value)}>
<CopyOutlined />
</IconButton>
</InputAdornment>
)
}}
/>
</div>
)}
</Stack>
</Box>
</Card>
</Grid>
</Grid>
</Card>
</Box>
</Container>
</ScrollX>
</MainCard>
);
};
export default VideoTranslate;
\ No newline at end of file
// import { Alert, Button, Card, CardActions, CardContent, CardHeader, Container, Grid, Typography } from '@mui/material';
// import Head from 'next/head';
// import { useCallback, useState } from 'react';
// import { ComingSoonIllustration } from 'assets/illustrations';
// import CustomBreadcrumbs from 'components/custom-breadcrumbs/CustomBreadcrumbs';
// import Iconify from 'components/iconify/Iconify';
// import HomeWidget from 'sections/@dashboard/spokenLanguageTranslation-module/HomeWidget';
// import _mock from '../../../_mock';
// import Editor from '../../../components/editor';
// import { useSettingsContext } from '../../../components/settings';
// import { Upload } from '../../../components/upload';
// import DashboardLayout from '../../../layout/dashboard';
// import {
// CarouselBasic3
// } from '../../../sections/_examples/extra/carousel';
// SpokenLanguageTranslationHomePage.getLayout = (page: React.ReactElement) => <DashboardLayout>{page}</DashboardLayout>;
// export default function SpokenLanguageTranslationHomePage() {
// const { themeStretch } = useSettingsContext();
// const [translateType, setTranslateType] = useState<"video" | "text">()
// const [file, setFile] = useState<File | string | null>(null);
// const [quillSimple, setQuillSimple] = useState('');
// const handleHomeWidgetOnClick = (value: string) => {
// if (!value) return
// if (value == "Video Translate") {
// setTranslateType("video")
// return
// }
// if (value == "Text Translate") {
// setTranslateType("text")
// return
// }
// }
// const handleDropSingleFile = useCallback((acceptedFiles: File[]) => {
// const file = acceptedFiles[0];
// if (file) {
// setFile(
// Object.assign(file, {
// preview: URL.createObjectURL(file),
// })
// );
// }
// }, []);
// const _carouselsExample = [...Array(5)].map((_, index) => ({
// id: _mock.id(index),
// title: _mock.text.title(index),
// image: _mock.image.cover(index),
// description: _mock.text.description(index),
// }));
// return (
// <>
// <Head>
// <title> Spoken Language Translation Home | SignLink </title>
// </Head>
// <Container maxWidth={themeStretch ? false : 'xl'}>
// <CustomBreadcrumbs
// heading="Spoken Language Translation"
// links={[
// {
// name: 'Dashboard',
// href: '#',
// icon: <Iconify icon="eva:home-fill" />,
// },
// { name: 'Spoken Language Translation Module', href: '#', icon: <Iconify icon="eva:cube-outline" /> },
// { name: 'Spoken Language Translation', icon: <Iconify icon="eva:cube-outline" /> },
// ]}
// />
// </Container>
// <Container maxWidth={themeStretch ? false : 'xl'}>
// <Grid container spacing={2} rowSpacing={3}>
// <Grid item xs={12} md={6} lg={6}>
// <HomeWidget
// title="Video Translate"
// subTitle="Spoken Language Video Convert to sign language"
// icon="eva:video-fill"
// color='warning'
// handleClick={handleHomeWidgetOnClick}
// />
// </Grid>
// <Grid item xs={12} md={6} lg={6}>
// <HomeWidget
// title="Text Translate"
// subTitle="Spoken Language Text Convert to sign language"
// icon="eva:text-fill"
// color="success"
// handleClick={handleHomeWidgetOnClick}
// />
// </Grid>
// {!translateType && <>
// <Grid item xs={12} md={12} lg={12}>
// <Alert severity='info' >Select a Translation type</Alert>
// </Grid>
// </>}
// {translateType == "video" && <>
// <Grid item xs={12} md={8} lg={8}>
// <Card>
// <CardHeader
// title="Upload Video"
// subheader="Upload you're video to convert to sigh language"
// />
// <CardContent>
// <Upload file={file} onDrop={handleDropSingleFile} onDelete={() => setFile(null)} />
// </CardContent>
// <CardActions>
// <Button variant="contained" color='error' fullWidth onClick={() => { setFile(null) }}>
// Reset
// </Button>
// <Button variant="contained" fullWidth>
// Convert
// </Button>
// </CardActions>
// </Card>
// </Grid>
// <Grid item xs={12} md={4} lg={4}>
// <Card>
// <CardHeader title="3D Model" />
// <CardContent>
// <Typography variant="h3" paragraph>
// Coming Soon!
// </Typography>
// <Typography sx={{ color: 'text.secondary' }}>
// We are currently working hard on this page!
// </Typography>
// <ComingSoonIllustration sx={{ my: 1, height: 200 }} />
// </CardContent>
// </Card>
// </Grid>
// </>}
// {translateType == "text" && <>
// <Grid item xs={12} md={8} lg={8}>
// <Card sx={{ height: "100%" }}>
// <CardHeader
// title="Enter text"
// subheader="Enter you're text to convert to sigh language"
// />
// <CardContent>
// <Editor
// simple
// id="simple-editor"
// value={quillSimple}
// onChange={(value) => setQuillSimple(value)}
// />
// </CardContent>
// <CardActions>
// <Button variant="contained" color='error' fullWidth onClick={() => { setQuillSimple('') }}>
// Reset
// </Button>
// <Button variant="contained" fullWidth>
// Convert
// </Button>
// </CardActions>
// </Card>
// </Grid>
// <Grid item xs={12} md={4} lg={4}>
// <Card>
// <CardHeader title="Converted Output" />
// <CardContent>
// <CarouselBasic3 data={_carouselsExample} />
// </CardContent>
// </Card>
// </Grid>
// </>}
// </Grid>
// </Container>
// </>
// );
// }
...@@ -36,8 +36,9 @@ const SSLTranslateProcess = Loadable(lazy(() => import('pages/ssl-translate/proc ...@@ -36,8 +36,9 @@ const SSLTranslateProcess = Loadable(lazy(() => import('pages/ssl-translate/proc
const LearningDashboard = Loadable(lazy(() => import('pages/learning-management/dashboard'))); const LearningDashboard = Loadable(lazy(() => import('pages/learning-management/dashboard')));
const LearningCurriculums = Loadable(lazy(() => import('pages/learning-management/learning-curriculums/list/list'))); 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 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 LearningCurriculumsSubscribedTutorial = Loadable(lazy(() => import('pages/learning-management/learning-curriculums-subscribed/tutorial/tutorial')));
const LearningFeedBack = Loadable(lazy(() => import('pages/learning-management/learning-feedback/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 // render - parameter curriculum management page
const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/curriculum-management/list/list'))); const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/curriculum-management/list/list')));
...@@ -45,6 +46,8 @@ const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/cur ...@@ -45,6 +46,8 @@ const CurriculumManagementList = Loadable(lazy(() => import('pages/parameter/cur
// render - parameter tutorial management page // render - parameter tutorial management page
const TutorialManagementList = Loadable(lazy(() => import('pages/parameter/tutorial-management/list/list'))); const TutorialManagementList = Loadable(lazy(() => import('pages/parameter/tutorial-management/list/list')));
// render - Video to Sign Language page
const VideoTranslation = Loadable(lazy(() => import('pages/video-to-sign-language/VideoTranslate/VideoTranslate')));
// render - audio-detection page // render - audio-detection page
...@@ -119,6 +122,15 @@ const MainRoutes = { ...@@ -119,6 +122,15 @@ const MainRoutes = {
] ]
}, },
{
path: 'video-to-sign-language',
children: [
{
path: 'VideoTranslate',
element: <VideoTranslation />
}
]
},
{ {
path: 'learning-management', path: 'learning-management',
children: [ children: [
...@@ -134,13 +146,27 @@ const MainRoutes = { ...@@ -134,13 +146,27 @@ const MainRoutes = {
path: 'curriculums-subscribed', path: 'curriculums-subscribed',
element: <LearningCurriculumsSubscribed /> element: <LearningCurriculumsSubscribed />
}, },
{
path: 'curriculums-subscribed-tutorial',
children: [
{
path: ':curriculumIndex', // Parameter for curriculum index
children: [
{
path: ':tutorialIndex', // Parameter for tutorial index
element: <LearningCurriculumsSubscribedTutorial />
}
]
}
]
},
{ {
path: 'lead-board', path: 'lead-board',
element: <LearningLeadBoard /> element: <MaintenanceUnderConstruction />
}, },
{ {
path: 'feedback', path: 'feedback',
element: <LearningFeedBack /> element: <MaintenanceUnderConstruction />
} }
] ]
}, },
......
import React, { useEffect } from 'react';
// third party
import { useInView } from 'react-intersection-observer';
import { motion, useAnimation } from 'framer-motion';
// =============================|| LANDING - FADE IN ANIMATION ||============================= //
function Animation({ children, variants }: { children: React.ReactElement; variants: any }) {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start('visible');
}
}, [controls, inView]);
return (
<motion.div
ref={ref}
animate={controls}
initial="hidden"
transition={{
x: {
type: 'spring',
stiffness: 150,
damping: 30,
duration: 0.5
},
opacity: { duration: 1 }
}}
variants={variants}
>
{children}
</motion.div>
);
}
export default Animation;
// material-ui
import {
Box,
Grid,
LinearProgress,
Stack,
Typography
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
// project import
import TutorialSection from './TutorialSection';
// types
import MainCard from 'components/MainCard';
import { ThemeDirection } from 'types/config';
import { curriculumTypeUserProgress } from "types/userProgress";
// assets
import { CheckCircleOutlined, UnorderedListOutlined } from '@ant-design/icons';
import Reader from 'assets/images/analytics/reader.svg';
import ReportCard from 'components/cards/statistics/ReportCard';
// ==============================|| Curriculum - Section ||============================== //
const CurriculumSection = ({ curriculum, curriculumIndex }: { curriculum: curriculumTypeUserProgress, curriculumIndex: number }) => {
const theme = useTheme();
return (
<>
<Stack spacing={2} sx={{ padding: 2 }}>
<MainCard title="Overview">
<Grid container spacing={2}>
<Grid
item
xs={7}
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">
{curriculum.curriculumDescription}
</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 }}>
{(curriculum?.curriculumMarkUser! / curriculum?.curriculumMark!) * 100}% Completed
</Typography>
<Box sx={{ maxWidth: '60%' }}>
<LinearProgress variant="determinate" color="success" value={(curriculum?.curriculumMarkUser! / curriculum?.curriculumMark!) * 100} />
</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 md={5} item>
<Grid container spacing={2}>
<Grid md={12} item>
<ReportCard primary={`LEVEL - ${curriculum.curriculumLevel}`} secondary="Curriculum Level" color={theme.palette.error.main} iconPrimary={UnorderedListOutlined} />
</Grid>
<Grid md={12} item>
<ReportCard primary={`Pass Mark - ${curriculum.curriculumMark}`} secondary="Curriculum Pass Mark" color={theme.palette.success.dark} iconPrimary={CheckCircleOutlined} />
</Grid>
</Grid>
</Grid>
</Grid>
</MainCard>
<MainCard title="Tutorials">
<Grid container spacing={2}>
{curriculum.tutorials && curriculum.tutorials?.map((tutorial, index) => {
return (<TutorialSection tutorial={tutorial!} curriculumIndex={curriculumIndex} tutorialIndex={index} />)
})}
</Grid>
</MainCard>
</Stack>
</>
);
};
export default CurriculumSection;
import { useState } from 'react';
import { useNavigate } from 'react-router';
// material-ui
import {
Box,
Button,
Grid,
Typography
} from '@mui/material';
// project import
import Animation from 'sections/learning-management/learning-curriculums-subscribed/Animation';
// types
import { tutorialTypeUserProgress } from "types/userProgress";
// assets
import { PlaySquareOutlined } from '@ant-design/icons';
import AnimateButton from 'components/@extended/AnimateButton';
import MainCard from 'components/MainCard';
// ==============================|| Tutorial - Section ||============================== //
const TutorialSection = ({ tutorial, tutorialIndex, curriculumIndex }: { tutorial: tutorialTypeUserProgress, curriculumIndex: number, tutorialIndex: number }) => {
let navigation = useNavigate()
const [desc, setDesc] = useState(tutorial.tutorialDescription?.slice(0, 100))
const [readMore, setReadMore] = useState(false)
return (
<>
<Grid item md={3}>
<Animation
variants={{
visible: { opacity: 1 },
hidden: { opacity: 0 }
}}
>
<MainCard contentSX={{ p: 3 }}>
<Grid container spacing={1.5}>
<Grid item xs={12}>
<Typography variant="h4" sx={{ fontWeight: 600, mt: 2 }}>
{tutorial.tutorialTitle}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body1" color="secondary" sx={{ textAlign: "justify" }}>
{desc}
<span style={{ fontWeight: "bold", cursor: "pointer" }}
onClick={() => {
if (!readMore) {
setDesc(tutorial.tutorialDescription)
setReadMore(true)
} else {
setDesc(tutorial.tutorialDescription?.slice(0, 100))
setReadMore(false)
}
}} color="secondary">
{readMore ? "Show Less" : "...Read More"}
</span>
</Typography>
</Grid>
<Grid item xs={12}>
<Box sx={{ display: 'inline-block' }}>
<AnimateButton>
<Button
variant="outlined"
endIcon={<PlaySquareOutlined />}
sx={{ my: 2 }}
onClick={() => { navigation(`/learning-management/curriculums-subscribed-tutorial/${curriculumIndex}/${tutorialIndex}`) }}
>
Start Tutorial
</Button>
</AnimateButton>
</Box>
</Grid>
<Grid item xs={12} sx={{ '& img': { mb: -3.75, width: `calc( 100% + 24px)` } }}>
<img src={tutorial.tutorialImage} alt="feature" />
</Grid>
</Grid>
</MainCard>
</Animation>
</Grid>
</>
)
}
export default TutorialSection;
\ No newline at end of file
// material-ui
import { CardContent, Grid, Skeleton, Stack, Avatar } from '@mui/material';
// project import
import MainCard from 'components/MainCard';
// assets
import { ContactsOutlined } from '@ant-design/icons';
// ===========================|| SKELETON - USER EMPTY CARD ||=========================== //
const UserCard = () => {
return (
<MainCard
border={false}
content={false}
boxShadow
sx={{ boxShadow: `rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px`, borderRadius: 2 }}
>
<CardContent sx={{ p: 2 }}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Stack flexDirection="row" alignItems="center">
<Avatar>
<ContactsOutlined style={{ visibility: 'inherit' }} />
</Avatar>
<Stack sx={{ width: '100%', pl: 2.5 }}>
<Skeleton animation={false} height={20} width="80%" />
<Skeleton animation={false} height={20} width="40%" />
</Stack>
</Stack>
</Grid>
<Grid item xs={12}>
<Skeleton animation={false} height={20} width={45} />
<Skeleton animation={false} height={20} />
<Stack direction="row" alignItems="center" spacing={1}>
<Skeleton animation={false} height={20} width={90} />
<Skeleton animation={false} height={20} width={38} />
</Stack>
</Grid>
<Grid item xs={12}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Grid container spacing={1}>
<Grid item>
<Skeleton animation={false} height={20} width={40} />
</Grid>
<Grid item>
<Skeleton animation={false} height={17} width={20} />
</Grid>
</Grid>
<Skeleton animation={false} height={32} width={47} />
</Stack>
</Grid>
</Grid>
</CardContent>
</MainCard>
);
};
export default UserCard;
// material-ui
import { Box, Grid, Stack, Typography } from '@mui/material';
// project import
import CurriculumCard from './CurriculumCard';
interface Props {
title: string;
}
// ==============================|| EMPTY STATE ||============================== //
const EmptyCurriculumCard = ({ title }: Props) => {
return (
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
sx={{
p: { xs: 2.5, sm: 6 },
height: `calc(100vh - 192px)`,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
bgcolor: 'transparent'
}}
>
<Grid container direction="column" justifyContent="center" alignItems="center">
<Grid item>
<Box sx={{ ml: -9, mb: { xs: -8, sm: -5 } }}>
<Box sx={{ position: 'relative' }}>
<CurriculumCard />
</Box>
<Box sx={{ position: 'relative', top: -120, left: 72 }}>
<CurriculumCard />
</Box>
</Box>
</Grid>
<Grid item>
<Stack spacing={1}>
<Typography align="center" variant="h4">
{title}
</Typography>
</Stack>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
);
};
export default EmptyCurriculumCard;
import React, { useEffect } from 'react';
// third party
import { useInView } from 'react-intersection-observer';
import { motion, useAnimation } from 'framer-motion';
// =============================|| LANDING - FADE IN ANIMATION ||============================= //
function Animation({ children, variants }: { children: React.ReactElement; variants: any }) {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start('visible');
}
}, [controls, inView]);
return (
<motion.div
ref={ref}
animate={controls}
initial="hidden"
transition={{
x: {
type: 'spring',
stiffness: 150,
damping: 30,
duration: 0.5
},
opacity: { duration: 1 }
}}
variants={variants}
>
{children}
</motion.div>
);
}
export default Animation;
import { useState } from 'react'; import { useEffect, useState } from 'react';
// material-ui // material-ui
import { import {
Box,
Button, Button,
Divider, CircularProgress,
Fade,
Grid, Grid,
List,
ListItem,
ListItemAvatar,
ListItemText,
Menu,
MenuItem,
Stack,
Typography Typography
} from '@mui/material'; } from '@mui/material';
// third-party // third-party
import { PDFDownloadLink } from '@react-pdf/renderer';
// project import // project import
import IconButton from 'components/@extended/IconButton';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
// assets // assets
import { MoreOutlined } from '@ant-design/icons'; import { MinusOutlined, PlusOutlined, SendOutlined } from '@ant-design/icons';
import Avatar from 'components/@extended/Avatar'; import AnimateButton from 'components/@extended/AnimateButton';
import curriculumLevels from 'data/curriculumLevels'; import useAuth from 'hooks/useAuth';
import { useDispatch, useSelector } from 'store';
import { openSnackbar } from 'store/reducers/snackbar';
import { addUserProgress, toInitialState } from 'store/reducers/userProgress';
import { curriculumType } from 'types/curriculum';
import Animation from './Animation';
import CurriculumPreview from './CurriculumPreview';
// types // types
export interface curriculumCardProps {
_id: number | string | undefined;
curriculumCode: string;
curriculumLevel: number;
curriculumName: string;
curriculumDescription: 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;
tutorialDescription: 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;
}
// ==============================|| CURRICULUM - CARD ||============================== // // ==============================|| CURRICULUM - CARD ||============================== //
const CurriculumCard = ({ curriculum }: { curriculum: curriculumCardProps }) => { const CurriculumCard = ({ curriculum }: { curriculum: curriculumType }) => {
// const [open, setOpen] = useState(false); let dispatch = useDispatch()
const { error, success, isLoading } = useSelector(state => state.userProgress);
const { user } = useAuth();
// const handleClickOpen = () => { const [open, setOpen] = useState(false);
// setOpen(true);
// };
// const handleClose = () => { const handleClickOpen = () => {
// setOpen(false); setOpen(true);
// };
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const openMenu = Boolean(anchorEl);
const handleMenuClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
}; };
const handleMenuClose = () => {
setAnchorEl(null); const handleClose = () => {
setOpen(false);
}; };
return ( const [desc, setDesc] = useState(curriculum.curriculumDescription?.slice(0, 100))
<> const [readMore, setReadMore] = useState(false)
<MainCard sx={{ height: 1, '& .MuiCardContent-root': { height: 1, display: 'flex', flexDirection: 'column' } }}> const [isSubscribed, setIsSubscribed] = useState(false)
<Grid id="print" container spacing={2.25}>
<Grid item xs={12}> /**
<List sx={{ width: 1, p: 0 }}> * API Config
<ListItem * User Progress API
disablePadding */
secondaryAction={
<IconButton edge="end" aria-label="comments" color="secondary" onClick={handleMenuClick}> const FollowCurriculum = () => {
<MoreOutlined style={{ fontSize: '1.15rem' }} /> if (!user) {
</IconButton> // User is missing
dispatch(
openSnackbar({
open: true,
message: 'User data is missing',
variant: 'alert',
alert: {
color: 'warning',
},
close: true,
})
);
} else if (!user.id) {
// User ID is missing
dispatch(
openSnackbar({
open: true,
message: 'User ID is missing',
variant: 'alert',
alert: {
color: 'warning',
},
close: true,
})
);
} else if (!curriculum) {
// Curriculum data is missing
dispatch(
openSnackbar({
open: true,
message: 'Curriculum data is missing',
variant: 'alert',
alert: {
color: 'warning',
},
close: true,
})
);
} else {
// All required data is present, dispatch addUserProgress
dispatch(addUserProgress(user.id, curriculum));
} }
>
<ListItemAvatar>
<Avatar alt={curriculum.curriculumName!} src={curriculum.curriculumImage!} />
</ListItemAvatar>
<ListItemText
primary={<Typography variant="subtitle1">{curriculum.curriculumName}</Typography>}
secondary={
<Typography variant="caption" color="secondary">
{curriculumLevels.find(level => level.id === curriculum.curriculumLevel)?.description || ""}
</Typography>
} }
/>
</ListItem> // handel error
</List> useEffect(() => {
<Menu if (error != null) {
id="fade-menu" dispatch(
MenuListProps={{ openSnackbar({
'aria-labelledby': 'fade-button' open: true,
}} //@ts-ignore
anchorEl={anchorEl} message: error ? error.Message : "Something went wrong ...",
open={openMenu} variant: 'alert',
onClose={handleMenuClose} alert: {
TransitionComponent={Fade} color: 'error'
anchorOrigin={{ },
vertical: 'bottom', close: true
horizontal: 'right' })
}} );
transformOrigin={{ dispatch(toInitialState())
vertical: 'top', }
horizontal: 'right' }, [error])
// handel success
useEffect(() => {
if (success != null) {
dispatch(
openSnackbar({
open: true,
message: success,
variant: 'alert',
alert: {
color: 'success'
},
close: true
})
);
dispatch(toInitialState())
}
}, [success])
useEffect(() => {
if (curriculum.subscribedUser) {
const userId = user?.id; // Assuming user.id is how you get the user's ID
const isUserSubscribed = curriculum.subscribedUser.includes(userId!);
if (isUserSubscribed) {
setIsSubscribed(true)
}
}
}, [curriculum, user]);
return (
<>
<Animation
variants={{
visible: { opacity: 1 },
hidden: { opacity: 0 }
}} }}
> >
<MenuItem sx={{ a: { textDecoration: 'none', color: 'inherit' } }}> <MainCard contentSX={{ p: 3 }}>
<PDFDownloadLink <Grid container spacing={1.5}>
document={<></>} fileName={`${curriculum.curriculumCode}-${curriculum.curriculumName}.pdf`}
// document={<ListSmallCard customer={customer} />} fileName={`Customer-${customer.fatherName}.pdf`}
>
Export PDF
</PDFDownloadLink>
</MenuItem>
</Menu>
</Grid>
<Grid item xs={12}> <Grid item xs={12}>
<Divider /> <Typography variant="h3" sx={{ fontWeight: 600, mt: 2 }}>
{curriculum.curriculumTitle}
</Typography>
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<Typography>{curriculum.curriculumDescription}</Typography> <Typography variant="body1" color="secondary" sx={{ textAlign: "justify" }}>
</Grid> {desc}
{/* <Grid item xs={12}> <span style={{ fontWeight: "bold", cursor: "pointer" }}
<Grid container spacing={1}> onClick={() => {
<Grid item xs={6}> if (!readMore) {
<List sx={{ p: 0, overflow: 'hidden', '& .MuiListItem-root': { px: 0, py: 0.5 } }}> setDesc(curriculum.curriculumDescription)
<ListItem> setReadMore(true)
<ListItemIcon> } else {
<MailOutlined /> setDesc(curriculum.curriculumDescription?.slice(0, 100))
</ListItemIcon> setReadMore(false)
<ListItemText primary={<Typography color="secondary">{customer.email}</Typography>} />
</ListItem>
<ListItem>
<ListItemIcon>
<PhoneOutlined />
</ListItemIcon>
<ListItemText
primary={
<Typography color="secondary">
<PatternFormat displayType="text" format="+1 (###) ###-####" mask="_" defaultValue={customer.contact} />
</Typography>
} }
/> }} color="secondary">
</ListItem> {readMore ? "Show Less" : "...Read More"}
</List> </span>
</Typography>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<List sx={{ p: 0, overflow: 'hidden', '& .MuiListItem-root': { px: 0, py: 0.5 } }}> <Box sx={{ display: 'inline-block', width: "100%" }}>
<ListItem> <AnimateButton>
<ListItemIcon> <Button
<EnvironmentOutlined /> fullWidth
</ListItemIcon> size='small'
<ListItemText primary={<Typography color="secondary">{customer.country}</Typography>} /> variant="outlined"
</ListItem> endIcon={isSubscribed ? <MinusOutlined /> : <PlusOutlined />}
<ListItem> sx={{ my: 2, width: "100%" }}
<ListItemIcon> onClick={() => {
<LinkOutlined /> if (!isSubscribed) {
</ListItemIcon> FollowCurriculum()
<ListItemText
primary={
<Link href="https://google.com" target="_blank" sx={{ textTransform: 'lowercase' }}>
https://{customer.firstName}.en
</Link>
} }
/>
</ListItem>
</List>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Box>
<Box
sx={{
display: 'flex',
flexWrap: 'wrap',
listStyle: 'none',
p: 0.5,
m: 0
}} }}
component="ul" color={isSubscribed ? 'secondary' : 'success'}
disabled={isLoading}
> >
{customer.skills.map((skill: string, index: number) => ( {isLoading ? <CircularProgress /> : <>{isSubscribed ? 'Un Follow Curriculum' : 'Follow Curriculum'} </>}
<ListItem disablePadding key={index} sx={{ width: 'auto', pr: 0.75, pb: 0.75 }}> </Button>
<Chip color="secondary" variant="outlined" size="small" label={skill} /> </AnimateButton>
</ListItem>
))}
</Box>
</Box> </Box>
</Grid> */}
</Grid> </Grid>
<Stack <Grid item xs={6}>
direction="row" <Box sx={{ display: 'inline-block', width: "100%" }}>
className="hideforPDf" <AnimateButton>
alignItems="center" <Button
spacing={1} fullWidth
justifyContent="space-between" size='small'
sx={{ mt: 'auto', mb: 0, pt: 2.25 }} variant="outlined"
endIcon={<SendOutlined />}
sx={{ my: 2, width: "100%" }}
onClick={handleClickOpen}
> >
<Typography variant="caption" color="secondary"> Preview Curriculum
Updated in {curriculum.createdAt?.toLocaleTimeString()}
</Typography>
<Button variant="outlined" size="small" onClick={() => {
// handleClickOpen()
}}>
Preview
</Button> </Button>
</Stack> </AnimateButton>
</Box>
</Grid>
<Grid item xs={12} sx={{ '& img': { marginBottom: '-3.75px', width: '100%', height: '456px', objectFit: 'cover' } }}>
<img src={curriculum.curriculumImage} alt="feature" />
</Grid>
</Grid>
</MainCard> </MainCard>
</Animation>
{/* edit customer dialog */} {/* edit curriculum dialog */}
{/* <CustomerPreview customer={customer} open={open} onClose={handleClose} /> */} <CurriculumPreview curriculum={curriculum} open={open} onClose={handleClose} />
</> </>
); );
}; };
......
import { useState } from 'react';
// material-ui
import {
Accordion, AccordionDetails, AccordionSummary,
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
List,
ListItem,
ListItemAvatar,
ListItemText,
Stack,
Tooltip,
Typography
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
// third-party
import { PDFDownloadLink } from '@react-pdf/renderer';
// project import
import Avatar from 'components/@extended/Avatar';
import IconButton from 'components/@extended/IconButton';
import { PopupTransition } from 'components/@extended/Transitions';
import MainCard from 'components/MainCard';
import SimpleBar from 'components/third-party/SimpleBar';
// assets
import { DownloadOutlined, TagOutlined } from '@ant-design/icons';
import curriculumLevels from 'data/curriculumLevels';
import { curriculumType } from 'types/curriculum';
// types
// ==============================|| Curriculum - CARD PREVIEW ||============================== //
export default function CurriculumPreview({ curriculum, open, onClose }: { curriculum: curriculumType; open: boolean; onClose: () => void }) {
const theme = useTheme();
const [expanded, setExpanded] = useState<string | false>('panel0');
const handleChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
setExpanded(newExpanded ? panel : false);
};
return (
<>
<Dialog
open={open}
TransitionComponent={PopupTransition}
keepMounted
onClose={onClose}
aria-describedby="alert-dialog-slide-description"
sx={{ '& .MuiDialog-paper': { width: 1024, maxWidth: 1, m: { xs: 1.75, sm: 2.5, md: 4 } } }}
>
<Box id="PopupPrint" sx={{ px: { xs: 2, sm: 3, md: 5 }, py: 1 }}>
<DialogTitle sx={{ px: 0 }}>
<List sx={{ width: 1, p: 0 }}>
<ListItem
disablePadding
secondaryAction={
<Stack direction="row" alignItems="center" justifyContent="center" spacing={0}>
<Tooltip title="Export">
<PDFDownloadLink
document={<></>} fileName={`${curriculum.curriculumCode}-${curriculum.curriculumTitle}.pdf`}
// document={<ListCard customer={customer} />} fileName={`Customer-${customer.fatherName}.pdf`}
>
<IconButton color="secondary">
<DownloadOutlined />
</IconButton>
</PDFDownloadLink>
</Tooltip>
{/* <Tooltip title="Edit">
<IconButton color="secondary" onClick={handleAdd}>
<EditOutlined />
</IconButton>
</Tooltip>
<Tooltip title="Delete" onClick={handleClose}>
<IconButton color="error">
<DeleteOutlined />
</IconButton>
</Tooltip> */}
</Stack>
}
>
<ListItemAvatar sx={{ mr: 0.75 }}>
<Avatar alt={curriculum.curriculumTitle} size="lg" src={curriculum.curriculumImage} />
</ListItemAvatar>
<ListItemText
primary={<Typography variant="h5">{curriculum.curriculumTitle}</Typography>}
secondary={<Typography color="secondary"> {curriculumLevels.find(level => level.id === curriculum.curriculumLevel)?.description || ""}</Typography>}
/>
</ListItem>
</List>
</DialogTitle>
<DialogContent dividers sx={{ px: 0 }}>
<SimpleBar sx={{ height: 'calc(100vh - 390px)' }}>
<Grid container spacing={3}>
<Grid item xs={12} sm={8} xl={12}>
<Grid container spacing={2.25}>
<Grid item xs={12}>
<MainCard title="Overview">
<Typography>
{curriculum.curriculumDescription}
</Typography>
</MainCard>
</Grid>
<Grid item xs={12}>
<MainCard title="Tutorials">
<Box
sx={{
'& .MuiAccordion-root': {
borderColor: theme.palette.divider,
'& .MuiAccordionSummary-root': {
bgcolor: 'transparent',
flexDirection: 'row',
'&:focus-visible': {
bgcolor: 'primary.lighter'
}
},
'& .MuiAccordionDetails-root': {
borderColor: theme.palette.divider
},
'& .Mui-expanded': {
color: theme.palette.primary.main
}
}
}}
>
{curriculum.tutorials?.map((tutorial, index) => {
return (
<>
<Accordion expanded={expanded === `panel${index}`} onChange={handleChange(`panel${index}`)}>
<AccordionSummary aria-controls={`panel${index}d-content`} id={`panel${index}d-header`}>
<Stack direction="row" spacing={1.5} alignItems="center">
<TagOutlined />
<Typography variant="h6">{tutorial.tutorialTitle}</Typography>
</Stack>
</AccordionSummary>
<AccordionDetails>
<Stack spacing={2}>
<Typography variant="h5">{tutorial.tutorialDescription}</Typography>
</Stack>
</AccordionDetails>
</Accordion>
</>
)
})}
</Box>
</MainCard>
</Grid>
</Grid>
</Grid>
</Grid>
</SimpleBar>
</DialogContent>
<DialogActions>
<Button color="error" onClick={onClose}>
Close
</Button>
</DialogActions>
</Box>
</Dialog>
</>
);
}
import { useState } from 'react'; import { useEffect, useState } from 'react';
// material-ui // material-ui
import { import {
...@@ -33,6 +33,12 @@ import IconButton from 'components/@extended/IconButton'; ...@@ -33,6 +33,12 @@ import IconButton from 'components/@extended/IconButton';
import { DeleteFilled } from '@ant-design/icons'; import { DeleteFilled } from '@ant-design/icons';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import curriculumLevels, { CurriculumLevelsType } from 'data/curriculumLevels'; import curriculumLevels, { CurriculumLevelsType } from 'data/curriculumLevels';
import useAuth from 'hooks/useAuth';
import { dispatch, useSelector } from 'store';
import { addCurriculum } from 'store/reducers/curriculum';
import { fetchTutorials } from 'store/reducers/tutorial';
import { Curriculum } from 'types/curriculum';
import { Tutorial } from 'types/tutorial';
import AlertCurriculumDelete from './AlertCurriculumDelete'; import AlertCurriculumDelete from './AlertCurriculumDelete';
// types // types
...@@ -60,25 +66,13 @@ const getInitialValues = (curriculum: FormikValues | null) => { ...@@ -60,25 +66,13 @@ const getInitialValues = (curriculum: FormikValues | null) => {
// ==============================|| CUSTOMER ADD / EDIT ||============================== // // ==============================|| CUSTOMER ADD / EDIT ||============================== //
export interface Props { export interface Props {
curriculum?: { curriculum: Curriculum;
_id: number | string | undefined;
curriculumCode: string;
curriculumLevel: number;
curriculumTitle: string;
curriculumDescription: string;
curriculumImage: string;
tutorials: string[];
status: number;
createdBy: string;
updatedBy: string;
createdAt: Date;
updatedAt: Date;
};
onCancel: () => void; onCancel: () => void;
} }
const AddEditCurriculum = ({ curriculum, onCancel }: Props) => { const AddEditCurriculum = ({ curriculum, onCancel }: Props) => {
const theme = useTheme(); const theme = useTheme();
const { user } = useAuth();
const isCreating = !curriculum; const isCreating = !curriculum;
...@@ -96,11 +90,26 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => { ...@@ -96,11 +90,26 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => {
validationSchema: CurriculumSchema, validationSchema: CurriculumSchema,
enableReinitialize: true, enableReinitialize: true,
onSubmit: (values, { setSubmitting, resetForm }) => { onSubmit: (values, { setSubmitting, resetForm }) => {
try { try {
if (curriculum) { if (curriculum) {
// PUT API // PUT API
} else { } else {
// POST API // POST API
// const dummyObject: Curriculum = curriculumReqOb
// dispatch(addCurriculum(dummyObject))
const req: Curriculum = {
curriculumCode: values.curriculumCode,
curriculumLevel: values.curriculumLevel!,
curriculumTitle: values.curriculumTitle,
curriculumDescription: values.curriculumDescription,
curriculumImage: values.curriculumImage,
tutorials: values.tutorials!,
createdBy: user?.name!,
};
dispatch(addCurriculum(req))
} }
resetForm() resetForm()
setSubmitting(false); setSubmitting(false);
...@@ -114,6 +123,16 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => { ...@@ -114,6 +123,16 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => {
const { errors, touched, handleSubmit, isSubmitting, getFieldProps, values } = formik; const { errors, touched, handleSubmit, isSubmitting, getFieldProps, values } = formik;
// const { handleSubmit, isSubmitting } = formik; // const { handleSubmit, isSubmitting } = formik;
const { tutorials } = useSelector(state => state.tutorial);
/**
* API Config
* Tutorial API
*/
useEffect(() => {
dispatch(fetchTutorials());
}, [dispatch])
return ( return (
<> <>
<FormikProvider value={formik}> <FormikProvider value={formik}>
...@@ -238,12 +257,12 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => { ...@@ -238,12 +257,12 @@ const AddEditCurriculum = ({ curriculum, onCancel }: Props) => {
<Autocomplete <Autocomplete
fullWidth fullWidth
id={`tutorials.${index}`} id={`tutorials.${index}`}
// value={tutorials.find((option) => option.id === formik.values.curriculumLevel) || null} value={tutorials.find((option) => option._id === formik.values.tutorials[index]) || null}
// onChange={(event: any, newValue: CurriculumLevelsType | null) => { onChange={(event: any, newValue: Tutorial | null) => {
// formik.setFieldValue(`tutorials.${index}`, newValue?.id); formik.setFieldValue(`tutorials.${index}`, newValue?._id);
// }} }}
options={[]} options={tutorials}
// getOptionLabel={(item) => `${item.description}`} getOptionLabel={(item) => `${item.tutorialTitle}`}
renderInput={(params) => { renderInput={(params) => {
return ( return (
<TextField <TextField
......
...@@ -7,20 +7,22 @@ import { PopupTransition } from 'components/@extended/Transitions'; ...@@ -7,20 +7,22 @@ import { PopupTransition } from 'components/@extended/Transitions';
// assets // assets
import { DeleteFilled } from '@ant-design/icons'; import { DeleteFilled } from '@ant-design/icons';
import { useDispatch } from 'store';
import { deleteCurriculum } from 'store/reducers/curriculum';
// types // types
interface Props { interface Props {
title: string; title: string;
open: boolean; open: boolean;
handleClose: (status: boolean) => void; handleClose: (status: boolean) => void;
deleteId: number | string | undefined; deleteId: string | undefined;
} }
// ==============================|| Curriculum - DELETE ||============================== // // ==============================|| Curriculum - DELETE ||============================== //
export default function AlertCurriculumDelete({ title, open, handleClose, deleteId }: Props) { export default function AlertCurriculumDelete({ title, open, handleClose, deleteId }: Props) {
// const dispatch = useDispatch(); const dispatch = useDispatch();
return ( return (
<Dialog <Dialog
...@@ -41,6 +43,14 @@ export default function AlertCurriculumDelete({ title, open, handleClose, delete ...@@ -41,6 +43,14 @@ export default function AlertCurriculumDelete({ title, open, handleClose, delete
<Typography variant="h4" align="center"> <Typography variant="h4" align="center">
Are you sure you want to delete? Are you sure you want to delete?
</Typography> </Typography>
<Typography align="center">
By deleting
<Typography variant="subtitle1" component="span">
{' '}
"{title}"{' '}
</Typography>
Curriculum, Its details & tasks will also be deleted.
</Typography>
</Stack> </Stack>
<Stack direction="row" spacing={2} sx={{ width: 1 }}> <Stack direction="row" spacing={2} sx={{ width: 1 }}>
...@@ -48,7 +58,7 @@ export default function AlertCurriculumDelete({ title, open, handleClose, delete ...@@ -48,7 +58,7 @@ export default function AlertCurriculumDelete({ title, open, handleClose, delete
Cancel Cancel
</Button> </Button>
<Button fullWidth color="error" variant="contained" onClick={() => { <Button fullWidth color="error" variant="contained" onClick={() => {
// dispatch(deleteNutrition(deleteId!)) dispatch(deleteCurriculum(deleteId!))
handleClose(true) handleClose(true)
}} autoFocus> }} autoFocus>
Delete Delete
......
...@@ -32,6 +32,10 @@ import IconButton from 'components/@extended/IconButton'; ...@@ -32,6 +32,10 @@ import IconButton from 'components/@extended/IconButton';
import { DeleteFilled } from '@ant-design/icons'; import { DeleteFilled } from '@ant-design/icons';
import { AccordionSummary, InputLabel, TextField } from '@mui/material'; import { AccordionSummary, InputLabel, TextField } from '@mui/material';
import MainCard from 'components/MainCard'; import MainCard from 'components/MainCard';
import useAuth from 'hooks/useAuth';
import { dispatch } from 'store';
import { addTutorial } from 'store/reducers/tutorial';
import { Tutorial } from 'types/tutorial';
import AlertTutorialDelete from './AlertTutorialDelete'; import AlertTutorialDelete from './AlertTutorialDelete';
// types // types
...@@ -53,6 +57,7 @@ const getInitialValues = (tutorial: FormikValues | null) => { ...@@ -53,6 +57,7 @@ const getInitialValues = (tutorial: FormikValues | null) => {
howToDo: "", howToDo: "",
referenceImage: "", referenceImage: "",
referenceVideo: "", referenceVideo: "",
taskItemMark: 0,
} }
] ]
} }
...@@ -67,37 +72,37 @@ const getInitialValues = (tutorial: FormikValues | null) => { ...@@ -67,37 +72,37 @@ const getInitialValues = (tutorial: FormikValues | null) => {
// ==============================|| CUSTOMER ADD / EDIT ||============================== // // ==============================|| CUSTOMER ADD / EDIT ||============================== //
export interface Props { export interface Props {
tutorial?: { tutorial?: Tutorial
_id: number | string | undefined
tutorialCode: string;
tutorialTitle: string;
tutorialDescription: string;
tutorialImage: string;
status: number;
createdBy: string;
updatedBy: string;
createdAt: Date;
updatedAt: Date;
taskItems: taskItemProps[]
};
onCancel: () => void; 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 AddEditTutorial = ({ tutorial, onCancel }: Props) => {
const theme = useTheme(); const theme = useTheme();
const { user } = useAuth();
const isCreating = !tutorial; const isCreating = !tutorial;
const TutorialSchema = Yup.object().shape({}); const TutorialSchema = Yup.object().shape({
tutorialCode: Yup.string().required(`Tutorial Code is required`),
tutorialTitle: Yup.string().required(`Tutorial Title is required`),
tutorialDescription: Yup.string().required(`Tutorial Description is required`),
tutorialImage: Yup.string().required(`Tutorial Image Ref is required`),
taskItems: Yup.array().of(
Yup.object().shape({
title: Yup.string().required(`Task Title is required`),
description: Yup.string().required(`Task Description is required`),
howToDo: Yup.string().required(`Task How To Do is required`),
referenceImage: Yup.string().required(`Task Reference Image is required`),
referenceVideo: Yup.string(),
taskItemMark: Yup.number().required(`Task Mark is required`).min(1, 'Task Mark must be greater than 0'),
})
).required(`Tutorial Task Item is required`),
status: Yup.number(),
createdBy: Yup.string(),
createdAt: Yup.date(),
updatedBy: Yup.string(),
updatedAt: Yup.date(),
});
const [openAlert, setOpenAlert] = useState(false); const [openAlert, setOpenAlert] = useState(false);
...@@ -116,6 +121,22 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -116,6 +121,22 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
// PUT API // PUT API
} else { } else {
// POST API // POST API
// const dummyObject: Tutorial = tutorialReqOb
// dispatch(addTutorial(dummyObject))
const req: Tutorial = {
tutorialCode: values.tutorialCode,
tutorialTitle: values.tutorialTitle,
tutorialImage: values.tutorialImage,
tutorialDescription: values.tutorialDescription,
taskItems: values.taskItems.map((item) => ({
...item,
howToDo: item.howToDo.split(','), // Split the comma-separated string into an array
})),
createdBy: user?.name!,
};
dispatch(addTutorial(req))
} }
resetForm() resetForm()
setSubmitting(false); setSubmitting(false);
...@@ -266,7 +287,7 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -266,7 +287,7 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={12}> <Grid item xs={6}>
<Stack spacing={1.25}> <Stack spacing={1.25}>
<InputLabel htmlFor={`taskItems.${index}.title`}>Task Title</InputLabel> <InputLabel htmlFor={`taskItems.${index}.title`}>Task Title</InputLabel>
<TextField <TextField
...@@ -274,8 +295,37 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -274,8 +295,37 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
id={`taskItems.${index}.title`} id={`taskItems.${index}.title`}
placeholder="Enter Task Title" placeholder="Enter Task Title"
{...getFieldProps(`taskItems.${index}.title`)} {...getFieldProps(`taskItems.${index}.title`)}
// error={Boolean(touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory)} error={Boolean(
// helperText={touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory} touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].title
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].title
}
/>
</Stack>
</Grid>
<Grid item xs={6}>
<Stack spacing={1.25}>
<InputLabel htmlFor={`taskItems.${index}.taskItemMark`}>Task Mark</InputLabel>
<TextField
fullWidth
id={`taskItems.${index}.taskItemMark`}
placeholder="Enter Task Mark"
{...getFieldProps(`taskItems.${index}.taskItemMark`)}
error={Boolean(
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].taskItemMark
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].taskItemMark
}
/> />
</Stack> </Stack>
</Grid> </Grid>
...@@ -287,8 +337,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -287,8 +337,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
id={`taskItems.${index}.referenceImage`} id={`taskItems.${index}.referenceImage`}
placeholder="Enter Task Reference Image" placeholder="Enter Task Reference Image"
{...getFieldProps(`taskItems.${index}.referenceImage`)} {...getFieldProps(`taskItems.${index}.referenceImage`)}
// error={Boolean(touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory)} error={Boolean(
// helperText={touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory} touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].referenceImage
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].referenceImage
}
/> />
</Stack> </Stack>
</Grid> </Grid>
...@@ -300,8 +358,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -300,8 +358,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
id={`taskItems.${index}.referenceVideo`} id={`taskItems.${index}.referenceVideo`}
placeholder="Enter Task Reference Video" placeholder="Enter Task Reference Video"
{...getFieldProps(`taskItems.${index}.referenceVideo`)} {...getFieldProps(`taskItems.${index}.referenceVideo`)}
// error={Boolean(touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory)} error={Boolean(
// helperText={touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory} touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].referenceVideo
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].referenceVideo
}
/> />
</Stack> </Stack>
</Grid> </Grid>
...@@ -313,8 +379,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -313,8 +379,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
id={`taskItems.${index}.description`} id={`taskItems.${index}.description`}
placeholder="Enter Task Description" placeholder="Enter Task Description"
{...getFieldProps(`taskItems.${index}.description`)} {...getFieldProps(`taskItems.${index}.description`)}
// error={Boolean(touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory)} error={Boolean(
// helperText={touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory} touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].description
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].description
}
/> />
</Stack> </Stack>
</Grid> </Grid>
...@@ -326,8 +400,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => { ...@@ -326,8 +400,16 @@ const AddEditTutorial = ({ tutorial, onCancel }: Props) => {
id={`taskItems.${index}.howToDo`} id={`taskItems.${index}.howToDo`}
placeholder="Enter Task How To Do" placeholder="Enter Task How To Do"
{...getFieldProps(`taskItems.${index}.howToDo`)} {...getFieldProps(`taskItems.${index}.howToDo`)}
// error={Boolean(touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory)} error={Boolean(
// helperText={touched.ingredientNutritions![index].nutritionCategory && errors.ingredientNutritions![index].nutritionCategory} touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].howToDo
)}
helperText={
touched.taskItems && touched.taskItems[index] &&
//@ts-ignore
errors.taskItems && errors.taskItems[index] && errors.taskItems[index].howToDo
}
/> />
</Stack> </Stack>
</Grid> </Grid>
......
...@@ -7,20 +7,22 @@ import { PopupTransition } from 'components/@extended/Transitions'; ...@@ -7,20 +7,22 @@ import { PopupTransition } from 'components/@extended/Transitions';
// assets // assets
import { DeleteFilled } from '@ant-design/icons'; import { DeleteFilled } from '@ant-design/icons';
import { useDispatch } from 'store';
import { deleteTutorial } from 'store/reducers/tutorial';
// types // types
interface Props { interface Props {
title: string; title: string;
open: boolean; open: boolean;
handleClose: (status: boolean) => void; handleClose: (status: boolean) => void;
deleteId: number | string | undefined; deleteId: string | undefined;
} }
// ==============================|| Tutorial - DELETE ||============================== // // ==============================|| Tutorial - DELETE ||============================== //
export default function AlertTutorialDelete({ title, open, handleClose, deleteId }: Props) { export default function AlertTutorialDelete({ title, open, handleClose, deleteId }: Props) {
// const dispatch = useDispatch(); const dispatch = useDispatch();
return ( return (
<Dialog <Dialog
...@@ -41,6 +43,14 @@ export default function AlertTutorialDelete({ title, open, handleClose, deleteId ...@@ -41,6 +43,14 @@ export default function AlertTutorialDelete({ title, open, handleClose, deleteId
<Typography variant="h4" align="center"> <Typography variant="h4" align="center">
Are you sure you want to delete? Are you sure you want to delete?
</Typography> </Typography>
<Typography align="center">
By deleting
<Typography variant="subtitle1" component="span">
{' '}
"{title}"{' '}
</Typography>
tutorial, Its details & tasks will also be deleted.
</Typography>
</Stack> </Stack>
<Stack direction="row" spacing={2} sx={{ width: 1 }}> <Stack direction="row" spacing={2} sx={{ width: 1 }}>
...@@ -48,7 +58,7 @@ export default function AlertTutorialDelete({ title, open, handleClose, deleteId ...@@ -48,7 +58,7 @@ export default function AlertTutorialDelete({ title, open, handleClose, deleteId
Cancel Cancel
</Button> </Button>
<Button fullWidth color="error" variant="contained" onClick={() => { <Button fullWidth color="error" variant="contained" onClick={() => {
// dispatch(deleteNutrition(deleteId!)) dispatch(deleteTutorial(deleteId!))
handleClose(true) handleClose(true)
}} autoFocus> }} autoFocus>
Delete Delete
......
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import { axiosServices } from 'utils/axios';
import { dispatch } from '../index';
// types
import { Curriculum, DefaultRootStateProps } from 'types/curriculum';
// ----------------------------------------------------------------------
const initialState: DefaultRootStateProps['curriculum'] = {
error: null,
success: null,
curriculums: [],
curriculum: null,
isLoading: false
};
const slice = createSlice({
name: 'curriculum',
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 CURRICULUM
addCurriculumSuccess(state, action) {
state.curriculums.push(action.payload);
state.success = "Curriculum created successfully."
},
// GET CURRICULUM
fetchCurriculumSuccess(state, action) {
state.curriculum = action.payload;
state.success = null
},
// GET ALL CURRICULUM
fetchCurriculumsSuccess(state, action) {
state.curriculums = action.payload;
state.success = null
},
// UPDATE CURRICULUM
updateCurriculumSuccess(state, action) {
const updatedCurriculumIndex = state.curriculums.findIndex(curriculum => curriculum._id === action.payload._id);
if (updatedCurriculumIndex !== -1) {
state.curriculums[updatedCurriculumIndex] = action.payload;
}
state.success = "Curriculum updated successfully."
},
// DELETE CURRICULUM
deleteCurriculumSuccess(state, action) {
state.curriculums = state.curriculums.filter(curriculum => curriculum._id !== action.payload);
state.success = "Curriculum deleted successfully."
},
}
});
// Reducer
export default slice.reducer;
// ----------------------------------------------------------------------
/**
* TO INITIAL STATE
* @returns
*/
export function toInitialState() {
return async () => {
dispatch(slice.actions.hasInitialState())
}
}
/**
* POST CURRICULUM
* @param newCurriculum
* @returns
*/
export function addCurriculum(newCurriculum: Curriculum) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.post('/rest_node/curriculum', newCurriculum);
dispatch(slice.actions.addCurriculumSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET CURRICULUM
* @param id
* @returns
*/
export function fetchCurriculum(id: number) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get(`/rest_node/curriculum/${id}`);
dispatch(slice.actions.fetchCurriculumSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET ALL CURRICULUMS
* @returns
*/
export function fetchCurriculums() {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get('/rest_node/curriculum');
dispatch(slice.actions.fetchCurriculumsSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* UPDATE CURRICULUM
* @param updatedCurriculum
* @returns
*/
export function updateCurriculum(updatedCurriculum: Curriculum) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.put(`/rest_node/curriculum/${updatedCurriculum._id}`, updatedCurriculum);
dispatch(slice.actions.updateCurriculumSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* DELETE CURRICULUM
* @param curriculumId
* @returns
*/
export function deleteCurriculum(curriculumId: string) {
return async () => {
dispatch(slice.actions.startLoading());
try {
await axiosServices.delete(`/rest_node/curriculum/${curriculumId}`);
dispatch(slice.actions.deleteCurriculumSuccess(curriculumId));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
...@@ -7,15 +7,19 @@ import storage from 'redux-persist/lib/storage'; ...@@ -7,15 +7,19 @@ import storage from 'redux-persist/lib/storage';
import calendar from './calendar'; import calendar from './calendar';
import cartReducer from './cart'; import cartReducer from './cart';
import chat from './chat'; import chat from './chat';
import curriculum from './curriculum';
import ingredient from './ingredient'; import ingredient from './ingredient';
import invoice from './invoice'; import invoice from './invoice';
import kanban from './kanban'; import kanban from './kanban';
import marksCalculator from './marksCalculator';
import menu from './menu'; import menu from './menu';
import nutrition from './nutrition'; import nutrition from './nutrition';
import productReducer from './product'; import productReducer from './product';
import snackbar from './snackbar'; import snackbar from './snackbar';
import subscription from './subscription'; import subscription from './subscription';
import tutorial from './tutorial';
import user from './user';
import userProgress from './userProgress';
// ==============================|| COMBINE REDUCERS ||============================== // // ==============================|| COMBINE REDUCERS ||============================== //
...@@ -37,7 +41,12 @@ const reducers = combineReducers({ ...@@ -37,7 +41,12 @@ const reducers = combineReducers({
invoice, invoice,
nutrition, nutrition,
ingredient, ingredient,
subscription subscription,
marksCalculator,
tutorial,
curriculum,
user,
userProgress
}); });
export default reducers; export default reducers;
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import { axiosServices } from 'utils/axios';
import { dispatch } from '../index';
// types
import { DefaultRootStateProps } from 'types/marksCalculator';
// ----------------------------------------------------------------------
const initialState: DefaultRootStateProps['marksCalculator'] = {
error: null,
success: null,
marksCalculator: null,
isLoading: false
};
const slice = createSlice({
name: 'marksCalculator',
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
marksCalculatorSuccess(state, action) {
state.marksCalculator = action.payload.result;
state.success = "Marks Calculated Successfully."
},
}
});
// Reducer
export default slice.reducer;
// ----------------------------------------------------------------------
/**
* TO INITIAL STATE
* @returns
*/
export function toInitialState() {
return async () => {
dispatch(slice.actions.hasInitialState())
}
}
/**
* POST Marks Calculator
* @param curriculumIndex
* @param tutorialIndex
* @param imageData
* @param targetClass
* @returns
*/
export function CalculateMarks(curriculumIndex: number, tutorialIndex: number, imageData: any, targetClass: string) {
return async () => {
dispatch(slice.actions.startLoading());
try {
// Construct the request body as needed (e.g., for formData)
const formData = new FormData();
formData.append('image', imageData);
formData.append('class', targetClass);
const response = await axiosServices.post(`/rest_node/marks-calculator/curriculum/${curriculumIndex}/tutorial/${tutorialIndex}`, formData);
dispatch(slice.actions.marksCalculatorSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
};
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import { axiosServices } from 'utils/axios';
import { dispatch } from '../index';
// types
import { DefaultRootStateProps, Tutorial } from 'types/tutorial';
// ----------------------------------------------------------------------
const initialState: DefaultRootStateProps['tutorial'] = {
error: null,
success: null,
tutorials: [],
tutorial: null,
isLoading: false
};
const slice = createSlice({
name: 'tutorial',
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 TUTORIAL
addTutorialSuccess(state, action) {
state.tutorials.push(action.payload);
state.success = "Tutorial created successfully."
},
// GET TUTORIAL
fetchTutorialSuccess(state, action) {
state.tutorial = action.payload;
state.success = null
},
// GET ALL TUTORIAL
fetchTutorialsSuccess(state, action) {
state.tutorials = action.payload;
state.success = null
},
// UPDATE TUTORIAL
updateTutorialSuccess(state, action) {
const updatedTutorialIndex = state.tutorials.findIndex(tutorial => tutorial._id === action.payload._id);
if (updatedTutorialIndex !== -1) {
state.tutorials[updatedTutorialIndex] = action.payload;
}
state.success = "Tutorial updated successfully."
},
// DELETE TUTORIAL
deleteTutorialSuccess(state, action) {
state.tutorials = state.tutorials.filter(tutorial => tutorial._id !== action.payload);
state.success = "Tutorial deleted successfully."
},
}
});
// Reducer
export default slice.reducer;
// ----------------------------------------------------------------------
/**
* TO INITIAL STATE
* @returns
*/
export function toInitialState() {
return async () => {
dispatch(slice.actions.hasInitialState())
}
}
/**
* POST TUTORIAL
* @param newTutorial
* @returns
*/
export function addTutorial(newTutorial: Tutorial) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.post('/rest_node/tutorial', newTutorial);
dispatch(slice.actions.addTutorialSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET TUTORIAL
* @param id
* @returns
*/
export function fetchTutorial(id: number) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get(`/rest_node/tutorial/${id}`);
dispatch(slice.actions.fetchTutorialSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET ALL TUTORIALS
* @returns
*/
export function fetchTutorials() {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get('/rest_node/tutorial');
dispatch(slice.actions.fetchTutorialsSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* UPDATE TUTORIAL
* @param updatedTutorial
* @returns
*/
export function updateTutorial(updatedTutorial: Tutorial) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.put(`/rest_node/tutorial/${updatedTutorial._id}`, updatedTutorial);
dispatch(slice.actions.updateTutorialSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* DELETE TUTORIAL
* @param tutorialId
* @returns
*/
export function deleteTutorial(tutorialId: string) {
return async () => {
dispatch(slice.actions.startLoading());
try {
await axiosServices.delete(`/rest_node/tutorial/${tutorialId}`);
dispatch(slice.actions.deleteTutorialSuccess(tutorialId));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
...@@ -103,7 +103,7 @@ export function addUser(newUser: User) { ...@@ -103,7 +103,7 @@ export function addUser(newUser: User) {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
const response = await axiosServices.post('/user/sign-up', newUser); const response = await axiosServices.post('/rest_node/user/sign-up', newUser);
dispatch(slice.actions.addUserSuccess(response.data)); dispatch(slice.actions.addUserSuccess(response.data));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
...@@ -123,7 +123,7 @@ export function fetchUser(id: number) { ...@@ -123,7 +123,7 @@ export function fetchUser(id: number) {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
const response = await axiosServices.get(`/user/${id}`); const response = await axiosServices.get(`/rest_node/user/${id}`);
dispatch(slice.actions.fetchUserSuccess(response.data)); dispatch(slice.actions.fetchUserSuccess(response.data));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
...@@ -143,7 +143,7 @@ export function fetchUsers(userType: string) { ...@@ -143,7 +143,7 @@ export function fetchUsers(userType: string) {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
const response = await axiosServices.get(`/user/all/type/${userType}`); const response = await axiosServices.get(`/rest_node/user/all/type/${userType}`);
dispatch(slice.actions.fetchUsersSuccess(response.data)); dispatch(slice.actions.fetchUsersSuccess(response.data));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
...@@ -162,7 +162,7 @@ export function fetchUsersByType() { ...@@ -162,7 +162,7 @@ export function fetchUsersByType() {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
const response = await axiosServices.get('/user/all'); const response = await axiosServices.get('/rest_node/user/all');
dispatch(slice.actions.fetchUsersSuccess(response.data)); dispatch(slice.actions.fetchUsersSuccess(response.data));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
...@@ -182,7 +182,7 @@ export function updateUser(updatedUser: User) { ...@@ -182,7 +182,7 @@ export function updateUser(updatedUser: User) {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
const response = await axiosServices.put(`/user/${updatedUser._id}`, updateUser); const response = await axiosServices.put(`/rest_node/user/${updatedUser._id}`, updateUser);
dispatch(slice.actions.updateUserSuccess(response.data)); dispatch(slice.actions.updateUserSuccess(response.data));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
...@@ -202,7 +202,7 @@ export function deleteNutrition(userId: number) { ...@@ -202,7 +202,7 @@ export function deleteNutrition(userId: number) {
dispatch(slice.actions.startLoading()); dispatch(slice.actions.startLoading());
try { try {
await axiosServices.delete(`/user/${userId}`); await axiosServices.delete(`/rest_node/user/${userId}`);
dispatch(slice.actions.deleteUserSuccess(userId)); dispatch(slice.actions.deleteUserSuccess(userId));
} catch (error) { } catch (error) {
dispatch(slice.actions.hasError(error)); dispatch(slice.actions.hasError(error));
......
// third-party
import { createSlice } from '@reduxjs/toolkit';
// project imports
import { axiosServices } from 'utils/axios';
import { dispatch } from '../index';
// types
import { DefaultRootStateProps, curriculumTypeUserProgress } from 'types/userProgress';
// ----------------------------------------------------------------------
const initialState: DefaultRootStateProps['userProgress'] = {
error: null,
success: null,
userProgresses: [],
userProgress: null,
isLoading: false
};
const slice = createSlice({
name: 'userProgress',
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_PROGRESS
addUpdateUserProgressSuccess(state, action) {
// state.userProgresses.push(action.payload);
state.success = "User Progress created or updated successfully."
},
// GET USER_PROGRESS
fetchUserProgressSuccess(state, action) {
state.userProgress = action.payload.userProgress;
state.success = null
},
// UPDATE USER_PROGRESS
updateUserProgressSuccess(state, action) {
// const updatedUserProgressIndex = state.userProgresses.findIndex(userProgress => userProgress._id === action.payload._id);
// if (updatedUserProgressIndex !== -1) {
// state.userProgresses[updatedUserProgressIndex] = action.payload;
// }
state.success = "UserProgress updated successfully."
},
}
});
// Reducer
export default slice.reducer;
// ----------------------------------------------------------------------
/**
* TO INITIAL STATE
* @returns
*/
export function toInitialState() {
return async () => {
dispatch(slice.actions.hasInitialState())
}
}
/**
* POST USER_PROGRESS
* @param newUserProgress
* @returns
*/
export function addUserProgress(userId: string, curriculum: curriculumTypeUserProgress) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.post('/rest_node/user-progress/subscribe-curriculum', { userId, curriculum });
dispatch(slice.actions.addUpdateUserProgressSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* GET USER_PROGRESS
* @param userId
* @returns
*/
export function fetchUserProgress(userId: string) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.get(`/rest_node/user-progress/${userId}`);
dispatch(slice.actions.fetchUserProgressSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
/**
* UPDATE USER_PROGRESS
* @param updatedUserProgress
* @returns
*/
export function updateUserProgress(userId: string, curriculumCode: string, tutorialCode: string, taskItemTitle: string, taskItemMarkUser: number, taskItemSpentTime: number) {
return async () => {
dispatch(slice.actions.startLoading());
try {
const response = await axiosServices.put(`/rest_node/user-progress/update-task-item-progress`, { userId, curriculumCode, tutorialCode, taskItemTitle, taskItemMarkUser, taskItemSpentTime });
dispatch(slice.actions.updateUserProgressSuccess(response.data));
} catch (error) {
dispatch(slice.actions.hasError(error));
} finally {
dispatch(slice.actions.finishLoading());
}
};
}
import { tutorialType } from "./tutorial"
export interface curriculumType {
_id?: string
curriculumCode: string
curriculumLevel?: number
curriculumTitle?: string
curriculumDescription?: string
curriculumImage?: string
curriculumMark?: number
tutorials?: tutorialType[],
status?: number
createdBy?: string
createdAt?: Date
updatedBy?: string
updatedAt?: Date
subscribedUser?: string[]
}
export type Curriculum = {
_id?: string
curriculumCode: string
curriculumLevel: number
curriculumTitle: string
curriculumDescription: string
curriculumImage: string
curriculumMark?: number
tutorials: string[],
status?: number
createdBy: string
createdAt?: Date
updatedBy?: string
updatedAt?: Date
};
export type Curriculums = {
_id?: string
curriculumCode: string
curriculumLevel: number
curriculumTitle: string
curriculumDescription: string
curriculumImage: string
curriculumMark: number
tutorials: tutorialType[],
status: number
createdBy: string
createdAt: Date
updatedBy?: string
updatedAt?: Date
};
export interface CurriculumStateProps {
curriculums: Curriculums[];
curriculum: Curriculum | null;
error: object | string | null;
success: object | string | null;
isLoading: boolean
}
export interface DefaultRootStateProps {
curriculum: CurriculumStateProps;
}
\ No newline at end of file
// Marks Calculator Type
export type MarksCalculator = {
predicted_class_name: string,
confidence: string,
status: string
};
export interface MarksCalculatorProps {
marksCalculator: MarksCalculator | null;
error: object | string | null;
success: object | string | null;
isLoading: boolean
}
export interface DefaultRootStateProps {
marksCalculator: MarksCalculatorProps;
}
\ No newline at end of file
export interface taskItemType {
_id?: string
title: string,
description?: string,
howToDo?: string[],
referenceImage?: string,
referenceVideo?: string,
taskItemMark?: number
}
\ No newline at end of file
import { taskItemType } from "./taskItem"
export interface tutorialType {
_id?: string
tutorialCode: string
tutorialTitle?: string
tutorialDescription?: string
tutorialImage?: string
tutorialMark?: number
taskItems?: taskItemType[]
status?: number
createdBy?: string
createdAt?: Date
updatedBy?: string
updatedAt?: Date
}
export type Tutorial = {
_id?: string
tutorialCode?: string
tutorialTitle?: string
tutorialDescription?: string
tutorialImage?: string
tutorialMark?: number
taskItems: taskItemType[]
status?: number
createdBy: string
createdAt?: Date
updatedBy?: string
updatedAt?: Date
};
export type Tutorials = {
_id?: string
tutorialCode?: string
tutorialTitle?: string
tutorialDescription?: string
tutorialImage?: string
tutorialMark: number
taskItems: taskItemType[]
status: number
createdBy: string
createdAt: Date
updatedBy?: string
updatedAt?: Date
};
export interface TutorialStateProps {
tutorials: Tutorials[];
tutorial: Tutorial | null;
error: object | string | null;
success: object | string | null;
isLoading: boolean
}
export interface DefaultRootStateProps {
tutorial: TutorialStateProps;
}
\ No newline at end of file
export interface userProgressType {
_id: string
userId: string
curriculums?: curriculumTypeUserProgress[]
totalCurriculumsMarks: number
totalCurriculumSpentTime: number
status: number
createdBy?: string
createdAt: Date
updatedBy?: string
updatedAt?: Date
}
export interface curriculumTypeUserProgress {
curriculumCode: string
curriculumLevel?: number
curriculumTitle?: string
curriculumDescription?: string
curriculumImage?: string
curriculumMark?: number
curriculumMarkUser?: number
curriculumSpentTime?: number
tutorials?: tutorialTypeUserProgress[],
}
export interface tutorialTypeUserProgress {
tutorialCode: string
tutorialTitle?: string
tutorialDescription?: string
tutorialImage?: string
tutorialMarks?: number
tutorialMarkUser?: number
tutorialSpentTime?: number
taskItems?: taskItemTypeUserProgress[]
}
export interface taskItemTypeUserProgress {
title: string,
description?: string,
howToDo?: string[],
referenceImage?: string,
referenceVideo?: string,
taskItemMark?: number
taskItemMarkUser?: number
taskItemSpentTime?: number
}
export type UserProgress = {
_id: string
userId: string
curriculums?: curriculumTypeUserProgress[]
totalCurriculumsMarks: number
totalCurriculumSpentTime: number
status: number
createdBy?: string
createdAt: Date
updatedBy?: string
updatedAt?: Date
};
export type UserProgresses = {
_id?: string
userId: string
curriculums?: curriculumTypeUserProgress[]
totalCurriculumsMarks: number
totalCurriculumSpentTime: number
status: number
createdBy?: string
createdAt: Date
updatedBy?: string
updatedAt?: Date
};
export interface UserProgressStateProps {
userProgresses: UserProgresses[];
userProgress: UserProgress | null;
error: object | string | null;
success: object | string | null;
isLoading: boolean
}
export interface DefaultRootStateProps {
userProgress: UserProgressStateProps;
}
\ No newline at end of file
...@@ -161,9 +161,12 @@ ...@@ -161,9 +161,12 @@
"learning-curriculums-subscribed": "My Courses", "learning-curriculums-subscribed": "My Courses",
"learning-lead-board": "Lead Board", "learning-lead-board": "Lead Board",
"learning-feedback": "Feedback", "learning-feedback": "Feedback",
"ssl-translate": "SSL Translate", "ssl-translate": "SSL Translation",
"emotion-detection": "Emotion Detection", "emotion-detection": "Emotion Detection",
"audio-detection": "Audio Detection", "audio-detection": "Audio Detection",
"video-detection": "Video Detection", "video-detection": "Video Detection",
"learning-dashboard": "Dashboard" "learning-dashboard": "Dashboard",
"learning-curriculums-subscribed-tutorial": "Tutorial",
"video-to-sign-language": "Sign Language Translate",
"video-translate": "Video Translator"
} }
...@@ -11116,6 +11116,11 @@ react-transition-group@^4.4.0, react-transition-group@^4.4.5: ...@@ -11116,6 +11116,11 @@ react-transition-group@^4.4.0, react-transition-group@^4.4.5:
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react-unity-webgl@^9.4.3:
version "9.4.3"
resolved "https://registry.yarnpkg.com/react-unity-webgl/-/react-unity-webgl-9.4.3.tgz#c13cadb8fd447d817a128e6e05975c4f4c9b8f74"
integrity sha512-P/NhKil8EZRtT3q87DC0EgxdNd3c5wa34DMWr5128r2bZojgVIJJu+b20RtGaJpW4lxg6SB2PNN4+R2QujKlDw==
react-webcam@^7.1.1: react-webcam@^7.1.1:
version "7.1.1" version "7.1.1"
resolved "https://registry.yarnpkg.com/react-webcam/-/react-webcam-7.1.1.tgz#e6290b192cde0d2a1039051a019a18e998d7fb39" resolved "https://registry.yarnpkg.com/react-webcam/-/react-webcam-7.1.1.tgz#e6290b192cde0d2a1039051a019a18e998d7fb39"
......
# Project ID: 2023-029 # Project ID: 2023-029
# Project Name: “Sign Language Translation with emotional base multi model,3D Avatar and Adaptive Learning.” # Project Name: “Sign Language Translation with emotional base multi model,3D Avatar and Adaptive Learning.”
## Main Objective ## Main Objective
...@@ -28,15 +29,40 @@ The main objective of this project is to develop a Sign Language Translation Sys ...@@ -28,15 +29,40 @@ The main objective of this project is to develop a Sign Language Translation Sys
### Member: Ranaweera R M S H (IT20251000) ### Member: Ranaweera R M S H (IT20251000)
**Research Question:** **Research Question:**
- How can sign language translation be achieved by identifying audio and text components in a video and translating them into sign language using 3D components? - How can sign language translation be achieved by identifying the audio components in a video and the text, and translating them into sign language using 3D components?
**Objectives:** **Objectives:**
- Pre-process video data to extract audio and text components. - Pre-process video data to extract audio components.
- Develop techniques to translate audio and text into sign language. - Develop techniques to translate audio into sign language.
- Integrate sign language translation with 3D components to create a visually appealing sign language video. - Develop techniques to translate text into sign language.
- Evaluate the accuracy of sign language translation and the overall effectiveness of the demonstration. - Integrate sign language translation with 3D components to create visually appealing sign language videos.
- Evaluate the accuracy of sign language translation.
- Evaluate the overall effectiveness of the sign language translation demonstration.
- Apply computer graphics techniques to enhance the realism and visual quality of the sign language animations. - Apply computer graphics techniques to enhance the realism and visual quality of the sign language animations.
## Novelty and Contributions
- **Novel Approach:**
> The research question proposes a novel approach to sign language translation by utilizing audio components from a video and text input. This approach combines audio analysis and text translation with 3D components to create visually appealing sign language videos.
- **Audio Component Extraction:**
> The research aims to develop techniques to pre-process video data and extract audio components. This extraction process is crucial for identifying and analyzing the audio elements necessary for sign language translation.
- **Audio-to-Sign Language Translation:**
> The research contributes to the development of techniques that translate audio components into sign language. By analyzing the audio data, the system can generate accurate sign language gestures and expressions corresponding to the spoken words or sounds.
- **Text-to-Sign Language Translation:**
> Another significant contribution is the development of techniques to translate text input into sign language. This enables users to input text directly, which the system converts into sign language gestures and expressions, providing a means of communication for individuals who are deaf or hard of hearing.
- **Integration of 3D Components:**
> The research focuses on integrating sign language translation with 3D components to enhance the visual quality and realism of the sign language animations. This integration adds depth and realism to the sign language gestures and creates visually appealing videos that effectively convey the intended message.
- **Evaluation of Translation Accuracy:**
> The research evaluates the accuracy of the sign language translation by comparing the generated sign language gestures with established sign language conventions. This evaluation ensures that the translations are linguistically and culturally appropriate, enhancing the overall effectiveness of the system.
- **Computer Graphics Enhancements:**
> The research contributes to the application of computer graphics techniques to enhance the realism and visual quality of the sign language animations. By leveraging graphics capabilities, the system can create visually engaging and expressive sign language videos, improving the user experience.
### Member: A V R Dilshan (IT20005276) ### Member: A V R Dilshan (IT20005276)
**Research Question:** **Research Question:**
......
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