├── .firebaserc ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── Contributing.md ├── README.md ├── babel.config.js ├── firebase.json ├── firestore.indexes.json ├── firestore.rules ├── package.json ├── public ├── _redirects ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── BsoC logo.svg │ ├── Discord.svg │ ├── Github.svg │ ├── Logo.svg │ ├── TPC logo.svg │ ├── arrow-204-32.png │ ├── delete-icon.svg │ ├── explore.png │ ├── fonts │ │ ├── IstokWeb-Regular.ttf │ │ └── PricedownBl-Regular 900.ttf │ ├── google-icon.png │ ├── instagram.svg │ ├── logo.png │ ├── main.css │ ├── noPR2.png │ ├── register.svg │ └── search.svg ├── components │ ├── FAQItem.vue │ ├── FAQS.vue │ ├── Footer.vue │ ├── Login.vue │ ├── Nav.vue │ ├── PreLoader.vue │ ├── ProjectsCard.vue │ ├── Signup.vue │ └── ToastComponent.vue ├── composables │ ├── addUsers.js │ ├── deleteDocuments.js │ ├── getCollection.js │ ├── getUser.js │ ├── useCollection.js │ ├── useLogin.js │ ├── useLoginCollection.js │ ├── useLogout.js │ ├── useSignInGoogle.js │ ├── useSignup.js │ └── useToast.js ├── firebase │ └── config.js ├── layouts │ ├── AuthLayout.vue │ ├── GeneralLayout.vue │ └── LandingLayout.vue ├── main.js ├── router │ └── index.js ├── store │ └── index.js └── views │ ├── Auth.vue │ ├── Dashboard.vue │ ├── Home.vue │ ├── LandingPage.vue │ ├── MyPR.vue │ ├── Projects.vue │ ├── SubmitPR.vue │ └── User.vue └── storage.rules /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "aperta-fons-bf53f" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | .DS_Store 3 | node_modules 4 | /dist 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | commit_message_file=$1 4 | commit_message=$(cat $commit_message_file) 5 | # echo "commit_message: $commit_message" 6 | 7 | # Define your desired commit message format 8 | commit_message_regex="^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\((.*?)\))?: (.*?)$" 9 | 10 | # Check if the commit message matches the desired format 11 | if ! echo "$commit_message" | grep -iqE "$commit_message_regex"; then 12 | echo "Invalid commit message format. Please use the following format: '(optional scope): '" 13 | echo "" 14 | echo "--------- Refer to Contributing.md for more information regarding convention ---------" 15 | echo "" 16 | echo "Example: ✅ 'feat(auth): Added login feature'" 17 | echo "Current message: ❌ '$commit_message'" 18 | echo "" 19 | exit 1 20 | fi -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.11.1 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | .DS_Store 3 | node_modules 4 | /dist 5 | 6 | # Markdown files 7 | **/*.md 8 | 9 | # Env files 10 | .env* 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": false, 4 | "singleQuote": true, 5 | "useTabs": true, 6 | "plugins": ["prettier-plugin-tailwindcss"] 7 | } 8 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 💻 2 | 3 | We recommend you to do local setup in a Linux environment. We will soon update the readme for Windows setup. 4 | 5 | If you're reading this, you're probably creating a Pull Request or planning to do so and that's great!🥳 6 | 7 | # How to Contribute 8 | 9 | 1. Fork this repository. 10 | 11 | 2. Clone the forked repository. 12 | 13 | ```bash 14 | git clone https://github.com//BSoC-Website.git 15 | ``` 16 | 17 | 3. Navigate to the project directory. 18 | 19 | ```bash 20 | cd BSoC-Website 21 | ``` 22 | 23 | 4. Create a New Branch 24 | 25 | ```bash 26 | git checkout -b 27 | ``` 28 | 29 | 5. Download Required Packages by running. 30 | 31 | ```bash 32 | npm i 33 | ``` 34 | 35 | >Note: It will take a couple of minutes(literally), be patient, ignore the warnings 36 | 37 | 6. Start the Server by Running. 38 | 39 | ```bash 40 | npm run serve 41 | ``` 42 | 43 | 7. Make changes in source code. 44 | 45 | 7. Stage your changes and commit 46 | 47 | ```bash 48 | git add 49 | ``` 50 | 51 | 8. Commit your changes 52 | 53 | ```bash 54 | git commit -m "(optional_scope): " 55 | ``` 56 | 57 | See [Conventional Commit Messages](#conventional-commit-messages) for convention 58 | 59 | 9. Push your local commits to the remote repo. 60 | 61 | 10. git push 62 | 63 | 11. Create a PR to develop repository. 64 | 65 | # For Creating a New Pull Request 💡💻 66 | 67 | 1. Navigate to the repository's directory: 68 | 69 | ```bash 70 | cd 71 | ``` 72 | 73 | 2. Ensure you are on the branch you want to use as the base branch: 74 | 75 | ```bash 76 | git checkout 77 | ``` 78 | 79 | 3. Create a new branch for your pull request: 80 | 81 | ```bash 82 | git branch 83 | ``` 84 | 85 | 4. To Switch to New created branch 86 | 87 | ```bash 88 | git checkout -b 89 | ``` 90 | 91 | 5. Stage and commit your changes: 92 | 93 | ```bash 94 | git add . 95 | git commit -m "Your commit message here" 96 | ``` 97 | 98 | 6. Replace "Your commit message here" with a descriptive message that summarizes the changes you made, Make sure to follow the convention. 99 | 100 | 7. Push the new branch to the remote repository: 101 | 102 | ```bash 103 | git push origin 104 | ``` 105 | 106 | This command pushes the new branch to the remote repository, making it available for others to see and review. 107 | 108 | - On GitHub navigate to the repository and locate the "New Pull Request" button. 109 | 110 | # Conventional Commit Messages 111 | 112 | In our project, we follow the convention of using conventional commit messages for all commits. Conventional commit messages provide a standardized format for commit messages, making it easier to understand and track changes in our codebase. 113 | 114 | A conventional commit message consists of a concise and structured format: 115 | 116 | ``` 117 | (optional_scope): 118 | ``` 119 | 120 | The message includes a type and a description, separated by a colon. Here's a breakdown of each component: 121 | 122 | Type: The type indicates the nature of the commit and should be selected from a predefined set of types that are relevant to the changes made. Some common types include: 123 | 124 | - feat: for a new feature implementation. 125 | - fix: for a bug fix. 126 | - docs: for documentation changes. 127 | - chore: for maintenance or general housekeeping tasks. 128 | - test: for adding or modifying tests. 129 | - refactor: for code refactoring without changing functionality. 130 | - style: for code style changes (e.g., formatting, indentation). 131 | - perf: for performance optimisations. 132 | 133 | Description: The description provides a brief summary of the changes made in the commit. It should be concise but descriptive enough to understand the purpose of the commit. 134 | 135 | ### Example: 136 | 137 | ```bash 138 | git commit -m "feat(frontend): Add navbar...." 139 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # 👨‍💻BSoC Website 4 | #### Hello developers✨!!..welcome to Bitbyte Summer of Code.. a wonderful chance for dedicated coders. 5 | 6 |
7 | 8 | This website seeks to connect you with open source, free software, and tech-related initiatives where you may study and develop code. The projects offer mentors who serve as guides throughout the whole process, from getting to know the community to contributing code. 9 | 10 | ## 🗒️Features 11 | - Supports you to start taking part in open source development 12 | - The leaderboard lists the top performers,which gets updated every day 13 | - Provides you with the chance to work with different people on the same project 14 | - Real-life experience about many fields 15 | - Contains FAQs to resolve your queries 16 | 17 | ## ⚙️Tech Stack 18 | - HTML5 19 | - CSS 20 | - VueJs 21 | - Firebase 22 | 23 | ## Engaging in the Project 24 | ### 🔶Prerequisites 25 | To run the project locally on your sysmtem , the following softwares must be installed . 26 | - Npm 10.x 27 | - Node 20.x 28 | 29 | You can check your node and npm versions by typing the mentioned commands in the terminal 30 | 31 | ```bash 32 | node -v 33 | npm -v 34 | ``` 35 | 36 | ## Run Locally 💻 37 | 38 | See [Contributing.md](Contributing.md) for step-by-step procedure. 39 | 40 | ## License 41 | The Programming Club, IIITDM Jabalpur 42 | 43 | ## Customize configuration 44 | See [Configuration Reference](https://cli.vuejs.org/config/). 45 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'], 3 | } 4 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "firestore": { 3 | "rules": "firestore.rules", 4 | "indexes": "firestore.indexes.json" 5 | }, 6 | "hosting": { 7 | "public": "dist", 8 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | }, 16 | "storage": { 17 | "rules": "storage.rules" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [], 3 | "fieldOverrides": [] 4 | } 5 | -------------------------------------------------------------------------------- /firestore.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | service cloud.firestore { 3 | match /databases/{database}/documents { 4 | match /{document=**} { 5 | allow read, write: if 6 | request.time < timestamp.date(2021, 10, 14); 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bsoc-website", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve", 7 | "build": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build", 8 | "production": "vue-cli-service build --mode production", 9 | "format": "prettier --write --ignore-unknown **/*", 10 | "prepare": "husky" 11 | }, 12 | "engines": { 13 | "node": "20.x", 14 | "npm": "10.x" 15 | }, 16 | "dependencies": { 17 | "@popperjs/core": "^2.11.8", 18 | "axios": "^1.7.2", 19 | "bootstrap": "^5.3.3", 20 | "core-js": "^3.8.3", 21 | "date-fns": "^2.24.0", 22 | "firebase": "^9.0.2", 23 | "hover.css": "^2.3.2", 24 | "dompurify": "^3.1.5", 25 | "mdb-vue-ui-kit": "^4.0.0", 26 | "particles.js": "^2.0.0", 27 | "popper": "^1.0.1", 28 | "vue": "^3.2.13", 29 | "vue-anchor-router-link": "^0.8.5", 30 | "vue-router": "^4.0.3", 31 | "vuex": "^4.0.0" 32 | }, 33 | "devDependencies": { 34 | "@vue/cli-plugin-babel": "~5.0.0", 35 | "@vue/cli-plugin-router": "~5.0.0", 36 | "@vue/cli-plugin-vuex": "~5.0.0", 37 | "@vue/cli-service": "~5.0.0", 38 | "@vue/compiler-sfc": "^3.2.13", 39 | "husky": "^9.0.11", 40 | "lint-staged": "^15.2.5", 41 | "prettier": "^3.2.5", 42 | "prettier-plugin-tailwindcss": "^0.6.0" 43 | }, 44 | "lint-staged": { 45 | "src/**/*.{js,vue}": [ 46 | "prettier --write --ignore-unknown" 47 | ], 48 | "public/**/*.html": [ 49 | "prettier --write --ignore-unknown" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | BSOC 16 | 17 | 18 | 19 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 34 | -------------------------------------------------------------------------------- /src/assets/BsoC logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/assets/Discord.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/Github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/Logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/TPC logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/arrow-204-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/arrow-204-32.png -------------------------------------------------------------------------------- /src/assets/delete-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/explore.png -------------------------------------------------------------------------------- /src/assets/fonts/IstokWeb-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/fonts/IstokWeb-Regular.ttf -------------------------------------------------------------------------------- /src/assets/fonts/PricedownBl-Regular 900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/fonts/PricedownBl-Regular 900.ttf -------------------------------------------------------------------------------- /src/assets/google-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/google-icon.png -------------------------------------------------------------------------------- /src/assets/instagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --primary_bg_col: #121519; 3 | --secondary_bg_col: #0890B2; 4 | --font_col: #efefef; 5 | --minor_col: #7904eb; 6 | --primary-font: Pricedown, serif; 7 | --secondary-font: Istok web, sans-serif; 8 | } 9 | #app { 10 | width: 100vw; 11 | margin: 0; 12 | padding: 0; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | padding: 0; 18 | overflow-x: hidden; 19 | } 20 | 21 | html { 22 | scroll-behavior: smooth; 23 | } 24 | 25 | ::-webkit-scrollbar { 26 | width: 20px; 27 | } 28 | 29 | ::-webkit-scrollbar-track { 30 | background-color: black; 31 | } 32 | 33 | ::-webkit-scrollbar-thumb { 34 | background-color: #075e7a; 35 | border-radius: 20px; 36 | border: 6px solid transparent; 37 | background-clip: content-box; 38 | } 39 | 40 | ::-webkit-scrollbar-thumb:hover { 41 | background-color: var(--secondary_bg_col); 42 | } 43 | -------------------------------------------------------------------------------- /src/assets/noPR2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsoc-bitbyte/BSoC-Website/417d9f8e6e6a2a94e8f82e05c60c53b342b08b73/src/assets/noPR2.png -------------------------------------------------------------------------------- /src/assets/register.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/FAQItem.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 47 | 48 | 180 | -------------------------------------------------------------------------------- /src/components/FAQS.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 115 | 139 | -------------------------------------------------------------------------------- /src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 48 | 49 | 190 | -------------------------------------------------------------------------------- /src/components/Login.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 124 | 125 | 160 | -------------------------------------------------------------------------------- /src/components/Nav.vue: -------------------------------------------------------------------------------- 1 | 241 | 346 | 347 | 544 | -------------------------------------------------------------------------------- /src/components/PreLoader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 131 | 132 | 419 | -------------------------------------------------------------------------------- /src/components/ProjectsCard.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | 43 | 165 | -------------------------------------------------------------------------------- /src/components/Signup.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 144 | 145 | 176 | -------------------------------------------------------------------------------- /src/components/ToastComponent.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | 22 | 75 | -------------------------------------------------------------------------------- /src/composables/addUsers.js: -------------------------------------------------------------------------------- 1 | import { projectFirestore } from '@/firebase/config' 2 | import { ref } from 'vue' 3 | 4 | const addUsers = (collection) => { 5 | const error = ref(null) 6 | 7 | const addDoc = async (user) => { 8 | error.value = null 9 | 10 | try { 11 | await projectFirestore.collection(collection).doc(user.uid).set(user) 12 | } catch (err) { 13 | console.log(err.message) 14 | error.value = 'Could not send message!!' 15 | } 16 | } 17 | 18 | return { error, addDoc } 19 | } 20 | 21 | export default addUsers 22 | -------------------------------------------------------------------------------- /src/composables/deleteDocuments.js: -------------------------------------------------------------------------------- 1 | import { getCollection } from '@/composables/getCollection' 2 | import { projectFirestore } from '@/firebase/config' 3 | import { errorToast, successToast } from './useToast' 4 | 5 | const deleteDocuments = async (n) => { 6 | const { err, documents } = getCollection('PriorityQueue') 7 | const colRef = await projectFirestore.collection('PriorityQueue') 8 | for (let i = 0; i < n && i < docs.value.length; i++) { 9 | const docRef = colRef.doc(docs[i].id) 10 | docRef 11 | .delete() 12 | .then(() => { 13 | console.log(docRef + ' deleted') 14 | }) 15 | .catch((e) => { 16 | console.log(e.message) 17 | }) 18 | } 19 | console.log('finished deleting') 20 | } 21 | 22 | const deletePr = async (id, doc, difficulty, uid) => { 23 | if ( 24 | doc.id == id && 25 | confirm( 26 | 'Are you sure you want to delete ? \nThis action can not be undone.' 27 | ) 28 | ) { 29 | const colRef = await projectFirestore.collection('dashboard-2024') 30 | const docRef = colRef.doc(doc.id) 31 | docRef 32 | .delete() 33 | .then(() => {}) 34 | .catch((e) => { 35 | errorToast('Error !', e.message) 36 | }) 37 | 38 | var current_score = 0 39 | var new_score = 0 40 | var current_prs = 0 41 | var new_prs = 0 42 | 43 | await projectFirestore 44 | .collection('userStats-2024') 45 | .doc(uid) 46 | .get() 47 | .then((snapshot) => { 48 | current_score = snapshot.data().score 49 | current_prs = snapshot.data().numberOfPRs 50 | new_score = current_score - difficulty 51 | new_prs = current_prs - 1 52 | }) 53 | .catch((e) => { 54 | errorToast('Error !', e.message) 55 | }) 56 | 57 | await projectFirestore 58 | .collection('userStats-2024') 59 | .doc(uid) 60 | .update({ score: new_score, numberOfPRs: new_prs }) 61 | 62 | successToast('Success !', 'PR deleted successfully') 63 | } 64 | } 65 | 66 | export { deleteDocuments, deletePr } 67 | -------------------------------------------------------------------------------- /src/composables/getCollection.js: -------------------------------------------------------------------------------- 1 | import { projectFirestore } from '@/firebase/config' 2 | import { ref, watchEffect } from 'vue' 3 | 4 | const getCollection = (collection) => { 5 | const documents = ref(null) 6 | const error = ref(null) 7 | 8 | let collectionRef = projectFirestore.collection(collection).orderBy('time') 9 | 10 | const unsub = collectionRef.onSnapshot( 11 | (snap) => { 12 | let results = [] 13 | snap.docs.forEach((doc) => { 14 | results.push({ ...doc.data(), id: doc.id, time_sec: doc.time }) 15 | }) 16 | documents.value = results.reverse() 17 | error.value = null 18 | }, 19 | (err) => { 20 | console.log(err.message) 21 | documents.value = null 22 | error.value = 'could not fetch data' 23 | } 24 | ) 25 | 26 | watchEffect((onInvalidate) => { 27 | onInvalidate(() => unsub()) 28 | }) 29 | 30 | return { error, documents } 31 | } 32 | 33 | const getAllUserStats = (collection) => { 34 | const documents = ref(null) 35 | const error = ref(null) 36 | 37 | let collectionRef = projectFirestore.collection(collection) 38 | const populate = collectionRef.onSnapshot( 39 | (snap) => { 40 | let results = [] 41 | snap.docs.forEach((doc) => { 42 | if (doc.data().displayName != null && doc.data().uid != null) { 43 | results.push({ ...doc.data(), id: doc.id, time_sec: doc.time }) 44 | } 45 | }) 46 | results.sort((a, b) => (a.score < b.score ? 1 : -1)) 47 | documents.value = results 48 | error.value = null 49 | }, 50 | (err) => { 51 | console.log(err.message) 52 | documents.value = null 53 | error.value = 'error in fetching user stats' 54 | } 55 | ) 56 | 57 | watchEffect((onInvalidate) => { 58 | onInvalidate(() => populate()) 59 | }) 60 | 61 | return { error, documents } 62 | } 63 | 64 | const getSingleUserStats = async (collection, uid) => { 65 | const documents = ref(null) 66 | const error = ref(null) 67 | 68 | try { 69 | const collectionRef = projectFirestore 70 | .collection(collection) 71 | .where('uid', '==', uid) 72 | const snap = await collectionRef.get() 73 | const results = [] 74 | 75 | snap.forEach((doc) => { 76 | results.push({ ...doc.data(), id: doc.id, time_sec: doc.time }) 77 | }) 78 | 79 | results.sort((a, b) => (a.score < b.score ? 1 : -1)) 80 | documents.value = results 81 | error.value = null 82 | } catch (err) { 83 | console.log(err.message) 84 | documents.value = null 85 | error.value = 'error in fetching user stats' 86 | } 87 | 88 | return { error, documents } 89 | } 90 | 91 | export { getAllUserStats, getCollection, getSingleUserStats } 92 | -------------------------------------------------------------------------------- /src/composables/getUser.js: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue' 2 | import { projectAuth } from '../firebase/config' 3 | 4 | // refs 5 | const user = ref(projectAuth.currentUser) 6 | 7 | // auth changes 8 | projectAuth.onAuthStateChanged((_user) => { 9 | console.log('User state change. Current user is:', _user) 10 | user.value = _user 11 | }) 12 | 13 | const getUser = () => { 14 | return { user } 15 | } 16 | 17 | export default getUser 18 | -------------------------------------------------------------------------------- /src/composables/useCollection.js: -------------------------------------------------------------------------------- 1 | import { projectFirestore } from '@/firebase/config' 2 | import { doc as firebaseDoc, getDoc, setDoc } from 'firebase/firestore' 3 | import { ref } from 'vue' 4 | 5 | const addDoc = async (collection, doc) => { 6 | const error = ref(null) 7 | 8 | try { 9 | await projectFirestore.collection(collection).add(doc) 10 | } catch (err) { 11 | console.log(err.message) 12 | error.value = 'Could not send message!!' 13 | } 14 | } 15 | 16 | const addUserStats = async (collection, doc) => { 17 | const error = ref(null) 18 | 19 | try { 20 | await projectFirestore.collection(collection).add(doc) 21 | } catch (err) { 22 | console.log(err.message) 23 | error.value = 'Could not add UserStats!!' 24 | } 25 | } 26 | 27 | const updateUserStats = async (collection, doc, id) => { 28 | try { 29 | const docRef = firebaseDoc(projectFirestore, collection, id) 30 | const existingDoc = await getDoc(docRef) 31 | let updatedScore = 0 32 | let numberOfPRs = 0 33 | if (!existingDoc.exists()) { 34 | console.log('No such document!') 35 | updatedScore = doc.difficulty 36 | numberOfPRs = 1 37 | await setDoc( 38 | docRef, 39 | { 40 | uid: doc.uid, 41 | score: updatedScore, 42 | displayName: doc.displayName, 43 | numberOfPRs: numberOfPRs, 44 | time: doc.time, 45 | }, 46 | { merge: true } 47 | ) 48 | console.log( 49 | 'Document successfully written!', 50 | 'score updated', 51 | updatedScore 52 | ) 53 | return 54 | } 55 | const existingScore = existingDoc.data().score 56 | updatedScore = parseInt(existingScore) + parseInt(doc.difficulty) 57 | numberOfPRs = parseInt(existingDoc.data().numberOfPRs) + 1 58 | 59 | await setDoc( 60 | docRef, 61 | { 62 | uid: doc.uid, 63 | score: updatedScore, 64 | displayName: doc.displayName, 65 | time: doc.time, 66 | numberOfPRs: numberOfPRs, 67 | }, 68 | { merge: true } 69 | ) 70 | 71 | console.log('Document successfully written!', 'score updated', updatedScore) 72 | } catch (err) { 73 | console.log(err.message) 74 | } 75 | } 76 | 77 | export { addDoc, addUserStats, updateUserStats } 78 | -------------------------------------------------------------------------------- /src/composables/useLogin.js: -------------------------------------------------------------------------------- 1 | import { projectAuth } from '@/firebase/config' 2 | import { ref } from 'vue' 3 | 4 | const error = ref(null) 5 | 6 | const login = async (email, password) => { 7 | error.value = null 8 | try { 9 | const res = await projectAuth.signInWithEmailAndPassword(email, password) 10 | error.value = null 11 | return res 12 | } catch (err) { 13 | console.log(err.message) 14 | error.value = 'Incorrect login credentials' 15 | } 16 | } 17 | 18 | const useLogin = () => { 19 | return { error, login } 20 | } 21 | 22 | export default useLogin 23 | -------------------------------------------------------------------------------- /src/composables/useLoginCollection.js: -------------------------------------------------------------------------------- 1 | import { projectFirestore } from '@/firebase/config' 2 | 3 | const useLoginCollection = async (id) => { 4 | return projectFirestore 5 | .collection('admins') 6 | .get() 7 | .then((t) => { 8 | return t.docs.map((doc) => doc.data()) 9 | }) 10 | } 11 | 12 | export default useLoginCollection 13 | -------------------------------------------------------------------------------- /src/composables/useLogout.js: -------------------------------------------------------------------------------- 1 | import { projectAuth } from '@/firebase/config' 2 | import { ref } from 'vue' 3 | 4 | const error = ref(null) 5 | 6 | const logout = async () => { 7 | error.value = null 8 | try { 9 | await projectAuth.signOut() 10 | } catch (err) { 11 | console.log(err) 12 | error.value = err.message 13 | } 14 | } 15 | 16 | const useLogout = () => { 17 | return { error, logout } 18 | } 19 | 20 | export default useLogout 21 | -------------------------------------------------------------------------------- /src/composables/useSignInGoogle.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/compat/app' 2 | import { ref } from 'vue' 3 | 4 | const err = ref(null) 5 | const googleLogin = async () => { 6 | const provider = new firebase.auth.GoogleAuthProvider() 7 | await firebase 8 | .auth() 9 | .signInWithPopup(provider) 10 | .then((result) => { 11 | const credential = 12 | firebase.auth.GoogleAuthProvider.credentialFromResult(result) 13 | const token = credential.accessToken 14 | const user = result.user 15 | }) 16 | .catch((err) => { 17 | err.value = err.message 18 | }) 19 | } 20 | 21 | const useSignInGoogle = () => { 22 | return { err, googleLogin } 23 | } 24 | 25 | export default useSignInGoogle 26 | -------------------------------------------------------------------------------- /src/composables/useSignup.js: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue' 2 | import { projectAuth } from '@/firebase/config' 3 | 4 | const error = ref(null) 5 | 6 | const signup = async (email, password, displayName) => { 7 | error.value = null 8 | try { 9 | const res = await projectAuth.createUserWithEmailAndPassword( 10 | email, 11 | password 12 | ) 13 | if (!res) { 14 | throw new Error('Could not complete signup!!') 15 | } 16 | await res.user.updateProfile({ displayName }) 17 | error.value = null 18 | return res 19 | } catch (err) { 20 | console.log(err.message) 21 | error.value = err.message 22 | } 23 | } 24 | 25 | const useSignup = () => { 26 | return { error, signup } 27 | } 28 | 29 | export default useSignup 30 | -------------------------------------------------------------------------------- /src/composables/useToast.js: -------------------------------------------------------------------------------- 1 | function sleep(ms) { 2 | return new Promise((resolve) => setTimeout(resolve, ms)) 3 | } 4 | 5 | export async function fade(element) { 6 | if (element != undefined) { 7 | await sleep(2000) 8 | element.style.opacity = '0' 9 | await sleep(500) 10 | element.style.display = 'none' 11 | element.style.opacity = '1' 12 | } 13 | } 14 | 15 | export function errorToast(error, message) { 16 | document.querySelector('.toaster').style.display = 'flex' 17 | document.querySelector('.toaster .card').style.backgroundColor = '#dc3545db' 18 | document.querySelector('.toaster .card-title').innerHTML = error 19 | document.querySelector('.toaster .card-text').innerHTML = message 20 | 21 | fade(document.querySelector('.toaster')) 22 | } 23 | 24 | export function successToast(title, message) { 25 | document.querySelector('.toaster').style.display = 'flex' 26 | document.querySelector('.toaster .card').style.backgroundColor = '#28a745db' 27 | document.querySelector('.toaster .card-title').innerHTML = title 28 | document.querySelector('.toaster .card-text').innerHTML = message 29 | 30 | fade(document.querySelector('.toaster')) 31 | } 32 | -------------------------------------------------------------------------------- /src/firebase/config.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/compat/app' 2 | import 'firebase/compat/firestore' 3 | import 'firebase/compat/auth' 4 | import 'firebase/compat/storage' 5 | 6 | const firebaseConfig = { 7 | apiKey: 'AIzaSyAiUtpvEBN8VYRWCEgmrNwMNkjW5p3IghU', 8 | authDomain: 'bsoc-23f7d.firebaseapp.com', 9 | projectId: 'bsoc-23f7d', 10 | storageBucket: 'bsoc-23f7d.appspot.com', 11 | messagingSenderId: '342829170628', 12 | appId: '1:342829170628:web:1c0dec609e854b169e2e91', 13 | measurementId: 'G-8FE62JB6CT', 14 | } 15 | 16 | firebase.initializeApp(firebaseConfig) 17 | 18 | const projectFirestore = firebase.firestore() 19 | const projectAuth = firebase.auth() 20 | const projectStorage = firebase.storage() 21 | 22 | const timestamp = firebase.firestore.FieldValue.serverTimestamp 23 | 24 | export { projectFirestore, projectAuth, projectStorage, timestamp } 25 | -------------------------------------------------------------------------------- /src/layouts/AuthLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/layouts/GeneralLayout.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | 35 | -------------------------------------------------------------------------------- /src/layouts/LandingLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.min.css' 2 | import 'bootstrap/dist/js/bootstrap.min.js' 3 | import './assets/main.css' 4 | 5 | import { projectAuth } from '@/firebase/config' 6 | import { createApp } from 'vue' 7 | import App from './App.vue' 8 | import router from './router' 9 | import store from './store' 10 | 11 | let app 12 | 13 | projectAuth.onAuthStateChanged(() => { 14 | if (!app) { 15 | app = createApp(App).use(router).use(store).mount('#app') 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { projectAuth } from '@/firebase/config' 2 | import { createRouter, createWebHistory } from 'vue-router' 3 | 4 | import AuthLayout from '@/layouts/AuthLayout.vue' 5 | import GeneralLayout from '@/layouts/GeneralLayout.vue' 6 | import LandingLayout from '@/layouts/LandingLayout.vue' 7 | 8 | import Login from '@/components/Login' 9 | import Signup from '@/components/Signup' 10 | import Auth from '@/views/Auth' 11 | import Dashboard from '@/views/Dashboard' 12 | import Home from '@/views/Home' 13 | import LandingPage from '@/views/LandingPage' 14 | import MyPR from '@/views/MyPR' 15 | import Projects from '@/views/Projects' 16 | import SubmitPR from '@/views/SubmitPR' 17 | import User from '@/views/User' 18 | 19 | const requireAuth = (to, from, next) => { 20 | let user = projectAuth.currentUser 21 | if (!user) { 22 | next({ path: '/auth' }) 23 | } else { 24 | next() 25 | } 26 | } 27 | 28 | const requireNoAuth = (to, from, next) => { 29 | let user = projectAuth.currentUser 30 | if (user) { 31 | next({ path: '/dashboard' }) 32 | } else { 33 | next() 34 | } 35 | } 36 | 37 | const routes = [ 38 | { 39 | path: '/', 40 | component: LandingLayout, 41 | children: [ 42 | { 43 | path: '', 44 | name: 'LandingPage', 45 | component: LandingPage, 46 | }, 47 | ], 48 | }, 49 | { 50 | path: '/auth', 51 | component: AuthLayout, 52 | children: [ 53 | { 54 | path: '', 55 | name: 'Auth', 56 | component: Auth, 57 | beforeEnter: requireNoAuth, 58 | }, 59 | { 60 | path: 'login', 61 | name: 'Login', 62 | component: Login, 63 | beforeEnter: requireNoAuth, 64 | }, 65 | { 66 | path: 'signup', 67 | name: 'Signup', 68 | component: Signup, 69 | beforeEnter: requireNoAuth, 70 | }, 71 | ], 72 | }, 73 | { 74 | path: '/', 75 | component: GeneralLayout, 76 | children: [ 77 | { 78 | path: 'dashboard', 79 | name: 'Dashboard', 80 | component: Dashboard, 81 | beforeEnter: requireAuth, 82 | }, 83 | 84 | { 85 | path: 'myPR', 86 | name: 'MyPR', 87 | component: MyPR, 88 | beforeEnter: requireAuth, 89 | }, 90 | { 91 | path: 'user/:uid', 92 | name: 'User', 93 | component: User, 94 | props: true, 95 | beforeEnter: requireAuth, 96 | }, 97 | { 98 | path: 'projects', 99 | name: 'Projects', 100 | component: Projects, 101 | }, 102 | { 103 | path: 'submit', 104 | name: 'SubmitPR', 105 | component: SubmitPR, 106 | beforeEnter: requireAuth, 107 | }, 108 | { 109 | path: 'home', 110 | name: 'Home', 111 | component: Home, 112 | }, 113 | ], 114 | }, 115 | ] 116 | 117 | const router = createRouter({ 118 | history: createWebHistory(process.env.BASE_URL), 119 | routes, 120 | }) 121 | 122 | export default router 123 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex' 2 | 3 | export default createStore({ 4 | state: { 5 | login: false, 6 | signup: false, 7 | }, 8 | mutations: { 9 | handleLoginComponent(state) { 10 | state.login = !state.login 11 | }, 12 | }, 13 | actions: {}, 14 | modules: {}, 15 | }) 16 | -------------------------------------------------------------------------------- /src/views/Auth.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/views/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 177 | 178 | 374 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 92 | 93 | 251 | 252 | 546 | -------------------------------------------------------------------------------- /src/views/LandingPage.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 186 | 187 | 532 | -------------------------------------------------------------------------------- /src/views/MyPR.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 124 | 125 | 247 | -------------------------------------------------------------------------------- /src/views/Projects.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 114 | 115 | 143 | -------------------------------------------------------------------------------- /src/views/SubmitPR.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 258 | 259 | 415 | -------------------------------------------------------------------------------- /src/views/User.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 64 | 65 | 156 | -------------------------------------------------------------------------------- /storage.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | service firebase.storage { 3 | match /b/{bucket}/o { 4 | match /{allPaths=**} { 5 | allow read, write: if request.auth!=null; 6 | } 7 | } 8 | } 9 | --------------------------------------------------------------------------------