├── package.json ├── index.ts ├── index.js └── tsconfig.json /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sms-mshsheikh", 3 | "version": "1.0.0", 4 | "description": "It's a simple CLI based Student Management System, with TypeScript, NodeJS & Inquirer by Muhammad Salman Hussain.", 5 | "main": "index.js", 6 | "type": "module", 7 | "bin": "index.js", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "inquirer": "^9.2.22" 16 | }, 17 | "devDependencies": { 18 | "@types/inquirer": "^9.0.7" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import inquirer from "inquirer"; 4 | 5 | class Student { 6 | static studentCount: number = 0; 7 | studentID: string; 8 | name: string; 9 | courses: string[]; 10 | balance: number; 11 | 12 | constructor(name: string) { 13 | this.studentID = this.generateStudentID(); 14 | this.name = name; 15 | this.courses = []; 16 | this.balance = 0; 17 | Student.studentCount++; 18 | } 19 | 20 | private generateStudentID(): string { 21 | return Math.floor(10000 + Math.random() * 90000).toString(); 22 | } 23 | 24 | enrollCourse(course: string): void { 25 | this.courses.push(course); 26 | console.log(`${this.name} enrolled in ${course} successfully.`); 27 | } 28 | 29 | viewBalance(): void { 30 | console.log(`${this.name}'s balance: $${this.balance}`); 31 | } 32 | 33 | payTuition(amount: number): void { 34 | this.balance += amount; 35 | console.log( 36 | `${this.name} paid $${amount}. Remaining balance: $${this.balance}` 37 | ); 38 | } 39 | 40 | showStatus(): void { 41 | console.log(`Student Name: ${this.name}`); 42 | console.log(`Student ID: ${this.studentID}`); 43 | console.log(`Courses Enrolled: ${this.courses.join(", ")}`); 44 | console.log(`Balance: $${this.balance}`); 45 | } 46 | } 47 | 48 | class StudentManagementSystem { 49 | students: Student[]; 50 | 51 | constructor() { 52 | this.students = []; 53 | } 54 | 55 | async addStudent(): Promise { 56 | const { name } = await inquirer.prompt([ 57 | { name: "name", message: "Enter student name:" }, 58 | ]); 59 | const newStudent = new Student(name); 60 | this.students.push(newStudent); 61 | console.log( 62 | `${newStudent.name} added to the system with ID ${newStudent.studentID}` 63 | ); 64 | } 65 | 66 | async enrollStudentInCourse(): Promise { 67 | const { studentID, course } = await inquirer.prompt([ 68 | { name: "studentID", message: "Enter student ID:" }, 69 | { name: "course", message: "Enter course name:" }, 70 | ]); 71 | 72 | const student = this.findStudentByID(studentID); 73 | if (student) { 74 | student.enrollCourse(course); 75 | } else { 76 | console.log("Student not found."); 77 | } 78 | } 79 | 80 | async viewStudentBalance(): Promise { 81 | const { studentID } = await inquirer.prompt([ 82 | { name: "studentID", message: "Enter student ID:" }, 83 | ]); 84 | const student = this.findStudentByID(studentID); 85 | if (student) { 86 | student.viewBalance(); 87 | } else { 88 | console.log("Student not found."); 89 | } 90 | } 91 | 92 | async payStudentTuition(): Promise { 93 | const { studentID, amount } = await inquirer.prompt([ 94 | { name: "studentID", message: "Enter student ID:" }, 95 | { name: "amount", message: "Enter tuition amount to pay:" }, 96 | ]); 97 | 98 | const student = this.findStudentByID(studentID); 99 | if (student) { 100 | student.payTuition(Number(amount)); 101 | } else { 102 | console.log("Student not found."); 103 | } 104 | } 105 | 106 | async showStudentStatus(): Promise { 107 | const { studentID } = await inquirer.prompt([ 108 | { name: "studentID", message: "Enter student ID:" }, 109 | ]); 110 | const student = this.findStudentByID(studentID); 111 | if (student) { 112 | student.showStatus(); 113 | } else { 114 | console.log("Student not found."); 115 | } 116 | } 117 | 118 | private findStudentByID(studentID: string): Student | undefined { 119 | return this.students.find((student) => student.studentID === studentID); 120 | } 121 | } 122 | 123 | async function main() { 124 | const sms = new StudentManagementSystem(); 125 | 126 | while (true) { 127 | const { action } = await inquirer.prompt([ 128 | { 129 | name: "action", 130 | message: "Select an action:", 131 | type: "list", 132 | choices: [ 133 | "Add Student", 134 | "Enroll Student in Course", 135 | "View Student Balance", 136 | "Pay Student Tuition", 137 | "Show Student Status", 138 | "Exit", 139 | ], 140 | }, 141 | ]); 142 | 143 | switch (action) { 144 | case "Add Student": 145 | await sms.addStudent(); 146 | break; 147 | 148 | case "Enroll Student in Course": 149 | await sms.enrollStudentInCourse(); 150 | break; 151 | 152 | case "View Student Balance": 153 | await sms.viewStudentBalance(); 154 | break; 155 | 156 | case "Pay Student Tuition": 157 | await sms.payStudentTuition(); 158 | break; 159 | 160 | case "Show Student Status": 161 | await sms.showStudentStatus(); 162 | break; 163 | 164 | case "Exit": 165 | console.log("Exiting Student Management System."); 166 | process.exit(0); 167 | } 168 | } 169 | } 170 | 171 | main(); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import inquirer from "inquirer"; 3 | class Student { 4 | static studentCount = 0; 5 | studentID; 6 | name; 7 | courses; 8 | balance; 9 | constructor(name) { 10 | this.studentID = this.generateStudentID(); 11 | this.name = name; 12 | this.courses = []; 13 | this.balance = 0; 14 | Student.studentCount++; 15 | } 16 | generateStudentID() { 17 | return Math.floor(10000 + Math.random() * 90000).toString(); 18 | } 19 | enrollCourse(course) { 20 | this.courses.push(course); 21 | console.log(`${this.name} enrolled in ${course} successfully.`); 22 | } 23 | viewBalance() { 24 | console.log(`${this.name}'s balance: $${this.balance}`); 25 | } 26 | payTuition(amount) { 27 | this.balance += amount; 28 | console.log(`${this.name} paid $${amount}. Remaining balance: $${this.balance}`); 29 | } 30 | showStatus() { 31 | console.log(`Student Name: ${this.name}`); 32 | console.log(`Student ID: ${this.studentID}`); 33 | console.log(`Courses Enrolled: ${this.courses.join(", ")}`); 34 | console.log(`Balance: $${this.balance}`); 35 | } 36 | } 37 | class StudentManagementSystem { 38 | students; 39 | constructor() { 40 | this.students = []; 41 | } 42 | async addStudent() { 43 | const { name } = await inquirer.prompt([ 44 | { name: "name", message: "Enter student name:" }, 45 | ]); 46 | const newStudent = new Student(name); 47 | this.students.push(newStudent); 48 | console.log(`${newStudent.name} added to the system with ID ${newStudent.studentID}`); 49 | } 50 | async enrollStudentInCourse() { 51 | const { studentID, course } = await inquirer.prompt([ 52 | { name: "studentID", message: "Enter student ID:" }, 53 | { name: "course", message: "Enter course name:" }, 54 | ]); 55 | const student = this.findStudentByID(studentID); 56 | if (student) { 57 | student.enrollCourse(course); 58 | } 59 | else { 60 | console.log("Student not found."); 61 | } 62 | } 63 | async viewStudentBalance() { 64 | const { studentID } = await inquirer.prompt([ 65 | { name: "studentID", message: "Enter student ID:" }, 66 | ]); 67 | const student = this.findStudentByID(studentID); 68 | if (student) { 69 | student.viewBalance(); 70 | } 71 | else { 72 | console.log("Student not found."); 73 | } 74 | } 75 | async payStudentTuition() { 76 | const { studentID, amount } = await inquirer.prompt([ 77 | { name: "studentID", message: "Enter student ID:" }, 78 | { name: "amount", message: "Enter tuition amount to pay:" }, 79 | ]); 80 | const student = this.findStudentByID(studentID); 81 | if (student) { 82 | student.payTuition(Number(amount)); 83 | } 84 | else { 85 | console.log("Student not found."); 86 | } 87 | } 88 | async showStudentStatus() { 89 | const { studentID } = await inquirer.prompt([ 90 | { name: "studentID", message: "Enter student ID:" }, 91 | ]); 92 | const student = this.findStudentByID(studentID); 93 | if (student) { 94 | student.showStatus(); 95 | } 96 | else { 97 | console.log("Student not found."); 98 | } 99 | } 100 | findStudentByID(studentID) { 101 | return this.students.find((student) => student.studentID === studentID); 102 | } 103 | } 104 | async function main() { 105 | const sms = new StudentManagementSystem(); 106 | while (true) { 107 | const { action } = await inquirer.prompt([ 108 | { 109 | name: "action", 110 | message: "Select an action:", 111 | type: "list", 112 | choices: [ 113 | "Add Student", 114 | "Enroll Student in Course", 115 | "View Student Balance", 116 | "Pay Student Tuition", 117 | "Show Student Status", 118 | "Exit", 119 | ], 120 | }, 121 | ]); 122 | switch (action) { 123 | case "Add Student": 124 | await sms.addStudent(); 125 | break; 126 | case "Enroll Student in Course": 127 | await sms.enrollStudentInCourse(); 128 | break; 129 | case "View Student Balance": 130 | await sms.viewStudentBalance(); 131 | break; 132 | case "Pay Student Tuition": 133 | await sms.payStudentTuition(); 134 | break; 135 | case "Show Student Status": 136 | await sms.showStudentStatus(); 137 | break; 138 | case "Exit": 139 | console.log("Exiting Student Management System."); 140 | process.exit(0); 141 | } 142 | } 143 | } 144 | main(); 145 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "NodeNext", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | "moduleResolution": "NodeNext", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------