├── .browserslistrc ├── .eslintrc.js ├── .firebase └── hosting.ZGlzdA.cache ├── .firebaserc ├── .gitattributes ├── .gitignore ├── README.md ├── babel.config.js ├── firebase.json ├── firestore.indexes.json ├── firestore.rules ├── functions ├── .gitignore ├── index.js ├── package-lock.json └── package.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── Icons │ │ ├── arrow-right-light.svg │ │ ├── bars-regular.svg │ │ ├── edit-regular.svg │ │ ├── envelope-regular.svg │ │ ├── instagram-brands.svg │ │ ├── linkedin-brands.svg │ │ ├── lock-alt-solid.svg │ │ ├── sign-out-alt-regular.svg │ │ ├── times-circle-light.svg │ │ ├── trash-regular.svg │ │ ├── twitter-brands.svg │ │ ├── user-alt-light.svg │ │ ├── user-crown-light.svg │ │ ├── whatsapp-brands.svg │ │ └── youtube-brands.svg │ ├── background.png │ ├── blogCards │ │ ├── stock-1.jpg │ │ ├── stock-2.jpg │ │ ├── stock-3.jpg │ │ └── stock-4.jpg │ ├── blogPhotos │ │ ├── beautiful-stories.jpg │ │ ├── coding.jpg │ │ └── designed-for-everyone.jpg │ └── logo.png ├── components │ ├── BlogCard.vue │ ├── BlogCoverPreview.vue │ ├── BlogPost.vue │ ├── Footer.vue │ ├── Loading.vue │ ├── Modal.vue │ └── Navigation.vue ├── firebase │ └── firebaseInit.js ├── main.js ├── router │ └── index.js ├── store │ └── index.js └── views │ ├── Admin.vue │ ├── BlogPreview.vue │ ├── Blogs.vue │ ├── CreatePost.vue │ ├── EditBlog.vue │ ├── ForgotPassword.vue │ ├── Home.vue │ ├── Login.vue │ ├── Profile.vue │ ├── Register.vue │ └── ViewBlog.vue ├── storage.rules └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | parserOptions: { 11 | parser: 'babel-eslint' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.firebase/hosting.ZGlzdA.cache: -------------------------------------------------------------------------------- 1 | index.html,1620760139988,77a2c9c6d80df1ae3bde8a70c8c25875e01cd37324518623ab6324a046f71f8b 2 | favicon.ico,1620760139988,1e71457865f706dc865b49a54a86e193818220d290b30226b6630a42faf1535d 3 | css/app.34410813.css,1620760139998,f521a653c7675e599a5797e210684d894e393958bb90e89bcffdc0179bb3ed50 4 | js/app.d9bb0b95.js,1620760140003,e4d1188e625699ae1f506e2d628be656ee65d0c830e6f043ae2572200c611de1 5 | img/designed-for-everyone.e5c67be6.jpg,1620760139999,733796e549513c66de7983f932b54fbdd23c06ce269670a07312c016d53f0ccd 6 | img/beautiful-stories.abd940b5.jpg,1620760139999,0dc1a3d8ed58ddc98dc35306d23ebaa12cf0211847d64a971fcd0172bfbcb798 7 | js/app.d9bb0b95.js.map,1620760139999,6f709a8803bd5702f1a17b733fa71f33bc30c920045e5675503431af0a0aad77 8 | img/background.048d49ff.png,1620760140003,601ceb5ea2529b848c3e87f64b5a6ec308d37d06da0ed892815a16ea51e42907 9 | js/chunk-vendors.fd168014.js,1620760140001,a6ccf1bb47775d21ecbbb16791d418a30607a0f4c66b8c9763d3f02f325e2c7f 10 | img/coding.7ab56a95.jpg,1620760139989,dc975d3c4933a62c43b5b71d11e7141bf0dd52d4a6cdacc0f0d18d69634c2e18 11 | js/chunk-vendors.fd168014.js.map,1620760140000,f25b17c8ac69729d37fdd1b9ace1e3ea03b281171ca63e3a8899badcaed1a7ed 12 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fireblogsyt-92263" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fireblogs 2 | 3 | ## Project Overview 4 | 5 | This is the completed source code for FireBlogs. This application is built with Vue.js (version 2) & Firebase. This video was created for Traversy Media, you can watch the tutorial [here:](https://www.youtube.com/watch?v=ISv22NNL-aE). 6 | 7 | ## Project setup 8 | 9 | ``` 10 | npm install 11 | ``` 12 | 13 | ### Compiles and hot-reloads for development 14 | 15 | ``` 16 | npm run serve 17 | ``` 18 | 19 | ### Compiles and minifies for production 20 | 21 | ``` 22 | npm run build 23 | ``` 24 | 25 | ### Lints and fixes files 26 | 27 | ``` 28 | npm run lint 29 | ``` 30 | 31 | ### Customize configuration 32 | 33 | See [Configuration Reference](https://cli.vuejs.org/config/). 34 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "firestore": { 3 | "rules": "firestore.rules", 4 | "indexes": "firestore.indexes.json" 5 | }, 6 | "storage": { 7 | "rules": "storage.rules" 8 | }, 9 | "hosting": { 10 | "public": "dist", 11 | "ignore": [ 12 | "firebase.json", 13 | "**/.*", 14 | "**/node_modules/**" 15 | ], 16 | "rewrites": [ 17 | { 18 | "source": "**", 19 | "destination": "/index.html" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /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, 6, 2); 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /functions/index.js: -------------------------------------------------------------------------------- 1 | const functions = require("firebase-functions"); 2 | const admin = require("firebase-admin"); 3 | admin.initializeApp(); 4 | 5 | exports.addAdminRole = functions.https.onCall((data, context) => { 6 | return admin 7 | .auth() 8 | .getUserByEmail(data.email) 9 | .then((user) => { 10 | return admin.auth().setCustomUserClaims(user.uid, { 11 | admin: true, 12 | }); 13 | }) 14 | .then(() => { 15 | return { 16 | message: `Success! ${data.email} has been made an admin!!`, 17 | }; 18 | }) 19 | .catch((err) => { 20 | console.log(err); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "12" 13 | }, 14 | "main": "index.js", 15 | "dependencies": { 16 | "firebase-admin": "^9.2.0", 17 | "firebase-functions": "^3.11.0" 18 | }, 19 | "devDependencies": { 20 | "firebase-functions-test": "^0.2.0" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fireblogs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "firebase": "^8.7.1", 13 | "quill": "^1.3.7", 14 | "quill-image-resize-module": "^3.0.0", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.2.0", 17 | "vue-svg-loader": "^0.16.0", 18 | "vue2-editor": "^2.10.2", 19 | "vuex": "^3.4.0" 20 | }, 21 | "devDependencies": { 22 | "@vue/cli-plugin-babel": "~4.5.0", 23 | "@vue/cli-plugin-eslint": "~4.5.0", 24 | "@vue/cli-plugin-router": "~4.5.0", 25 | "@vue/cli-plugin-vuex": "~4.5.0", 26 | "@vue/cli-service": "~4.5.0", 27 | "babel-eslint": "^10.1.0", 28 | "eslint": "^6.7.2", 29 | "eslint-plugin-vue": "^6.2.2", 30 | "node-sass": "^4.12.0", 31 | "sass-loader": "^8.0.2", 32 | "vue-template-compiler": "^2.6.11" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 51 | 52 | 179 | -------------------------------------------------------------------------------- /src/assets/Icons/arrow-right-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/bars-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/edit-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/envelope-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/instagram-brands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/linkedin-brands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/lock-alt-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/sign-out-alt-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/times-circle-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/trash-regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/twitter-brands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/user-alt-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/user-crown-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/whatsapp-brands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/Icons/youtube-brands.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/background.png -------------------------------------------------------------------------------- /src/assets/blogCards/stock-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogCards/stock-1.jpg -------------------------------------------------------------------------------- /src/assets/blogCards/stock-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogCards/stock-2.jpg -------------------------------------------------------------------------------- /src/assets/blogCards/stock-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogCards/stock-3.jpg -------------------------------------------------------------------------------- /src/assets/blogCards/stock-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogCards/stock-4.jpg -------------------------------------------------------------------------------- /src/assets/blogPhotos/beautiful-stories.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogPhotos/beautiful-stories.jpg -------------------------------------------------------------------------------- /src/assets/blogPhotos/coding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogPhotos/coding.jpg -------------------------------------------------------------------------------- /src/assets/blogPhotos/designed-for-everyone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/blogPhotos/designed-for-everyone.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thaerfayyad/fireBlogs-vuejs-backend-firebase/e9c9b055d88cadb14ecb7ffa3a7f797b6d505b32/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/BlogCard.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 49 | 50 | 157 | -------------------------------------------------------------------------------- /src/components/BlogCoverPreview.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | 29 | 73 | -------------------------------------------------------------------------------- /src/components/BlogPost.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 39 | 40 | 155 | -------------------------------------------------------------------------------- /src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 63 | 64 | 182 | -------------------------------------------------------------------------------- /src/components/Loading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 42 | -------------------------------------------------------------------------------- /src/components/Modal.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | 52 | -------------------------------------------------------------------------------- /src/components/Navigation.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 124 | 125 | 311 | -------------------------------------------------------------------------------- /src/firebase/firebaseInit.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase/app"; 2 | import "firebase/firestore"; 3 | 4 | var firebaseConfig = { 5 | // ENTER YOUR CONFIG HERE 6 | apiKey: "", 7 | authDomain: "", 8 | projectId: "", 9 | storageBucket: "", 10 | messagingSenderId: "", 11 | appId: "" 12 | }; 13 | 14 | const firebaseApp = firebase.initializeApp(firebaseConfig); 15 | const timestamp = firebase.firestore.FieldValue.serverTimestamp; 16 | 17 | export { timestamp }; 18 | export default firebaseApp.firestore(); 19 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | import Vue2Editor from "vue2-editor"; 6 | import firebase from "firebase/app"; 7 | import "firebase/auth"; 8 | 9 | Vue.use(Vue2Editor); 10 | 11 | Vue.config.productionTip = false; 12 | 13 | let app; 14 | firebase.auth().onAuthStateChanged(() => { 15 | if (!app) { 16 | new Vue({ 17 | router, 18 | store, 19 | render: (h) => h(App), 20 | }).$mount("#app"); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import Home from "../views/Home.vue"; 4 | import Blogs from "../views/Blogs.vue"; 5 | import Login from "../views/Login.vue"; 6 | import Register from "../views/Register.vue"; 7 | import ForgotPassword from "../views/ForgotPassword.vue"; 8 | import Profile from "../views/Profile.vue"; 9 | import Admin from "../views/Admin.vue"; 10 | import CreatePost from "../views/CreatePost.vue"; 11 | import BlogPreview from "../views/BlogPreview.vue"; 12 | import ViewBlog from "../views/ViewBlog.vue"; 13 | import EditBlog from "../views/EditBlog.vue"; 14 | import firebase from "firebase/app"; 15 | import "firebase/auth"; 16 | 17 | Vue.use(VueRouter); 18 | 19 | const routes = [ 20 | { 21 | path: "/", 22 | name: "Home", 23 | component: Home, 24 | meta: { 25 | title: "Home", 26 | requiresAuth: false, 27 | }, 28 | }, 29 | { 30 | path: "/blogs", 31 | name: "Blogs", 32 | component: Blogs, 33 | meta: { 34 | title: "Blogs", 35 | requiresAuth: false, 36 | }, 37 | }, 38 | { 39 | path: "/login", 40 | name: "Login", 41 | component: Login, 42 | meta: { 43 | title: "Login", 44 | requiresAuth: false, 45 | }, 46 | }, 47 | { 48 | path: "/register", 49 | name: "Register", 50 | component: Register, 51 | meta: { 52 | title: "Register", 53 | requiresAuth: false, 54 | }, 55 | }, 56 | { 57 | path: "/forgot-password", 58 | name: "ForgotPassword", 59 | component: ForgotPassword, 60 | meta: { 61 | title: "Forgot Password", 62 | requiresAuth: false, 63 | }, 64 | }, 65 | { 66 | path: "/profile", 67 | name: "Profile", 68 | component: Profile, 69 | meta: { 70 | title: "Profile", 71 | requiresAuth: true, 72 | }, 73 | }, 74 | { 75 | path: "/admin", 76 | name: "Admin", 77 | component: Admin, 78 | meta: { 79 | title: "Admin", 80 | requiresAuth: true, 81 | requiresAdmin: true, 82 | }, 83 | }, 84 | { 85 | path: "/create-post", 86 | name: "CreatePost", 87 | component: CreatePost, 88 | meta: { 89 | title: "Create Post", 90 | // requiresAuth: true, 91 | // requiresAdmin: true, 92 | }, 93 | }, 94 | { 95 | path: "/post-preview", 96 | name: "BlogPreview", 97 | component: BlogPreview, 98 | meta: { 99 | title: "Preview Blog Post", 100 | // requiresAuth: true, 101 | // requiresAdmin: true, 102 | }, 103 | }, 104 | { 105 | path: "/view-blog/:blogid", 106 | name: "ViewBlog", 107 | component: ViewBlog, 108 | meta: { 109 | title: "View Blog Post", 110 | requiresAuth: false, 111 | }, 112 | }, 113 | { 114 | path: "/edit-blog/:blogid", 115 | name: "EditBlog", 116 | component: EditBlog, 117 | meta: { 118 | title: "Edit Blog Post", 119 | // requiresAuth: true, 120 | // requiresAdmin: true, 121 | }, 122 | }, 123 | ]; 124 | 125 | const router = new VueRouter({ 126 | mode: "history", 127 | base: process.env.BASE_URL, 128 | routes, 129 | scrollBehavior() { 130 | return { x: 0, y: 0 }; 131 | }, 132 | }); 133 | 134 | router.beforeEach((to, from, next) => { 135 | document.title = `${to.meta.title} | FireBlog`; 136 | next(); 137 | }); 138 | 139 | router.beforeEach(async (to, from, next) => { 140 | let user = firebase.auth().currentUser; 141 | let admin = null; 142 | if (user) { 143 | let token = await user.getIdTokenResult(); 144 | admin = token.claims.admin; 145 | } 146 | if (to.matched.some((res) => res.meta.requiresAuth)) { 147 | if (user) { 148 | if (to.matched.some((res) => res.meta.requiresAdmin)) { 149 | if (admin) { 150 | return next(); 151 | } 152 | return next({ name: "Home" }); 153 | } 154 | return next(); 155 | } 156 | return next({ name: "Home" }); 157 | } 158 | return next(); 159 | }); 160 | 161 | export default router; 162 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import firebase from "firebase/app"; 4 | import "firebase/auth"; 5 | import db from "../firebase/firebaseInit"; 6 | 7 | Vue.use(Vuex); 8 | 9 | export default new Vuex.Store({ 10 | state: { 11 | blogPosts: [], 12 | postLoaded: null, 13 | blogHTML: "Write your blog title here...", 14 | blogTitle: "", 15 | blogPhotoName: "", 16 | blogPhotoFileURL: null, 17 | blogPhotoPreview: null, 18 | editPost: null, 19 | user: null, 20 | profileAdmin: null, 21 | profileEmail: null, 22 | profileFirstName: null, 23 | profileLastName: null, 24 | profileUsername: null, 25 | profileId: null, 26 | profileInitials: null, 27 | }, 28 | getters: { 29 | blogPostsFeed(state) { 30 | return state.blogPosts.slice(0, 2); 31 | }, 32 | blogPostsCards(state) { 33 | return state.blogPosts.slice(2, 6); 34 | }, 35 | }, 36 | mutations: { 37 | newBlogPost(state, payload) { 38 | state.blogHTML = payload; 39 | }, 40 | updateBlogTitle(state, payload) { 41 | state.blogTitle = payload; 42 | }, 43 | fileNameChange(state, payload) { 44 | state.blogPhotoName = payload; 45 | }, 46 | createFileURL(state, payload) { 47 | state.blogPhotoFileURL = payload; 48 | }, 49 | openPhotoPreview(state) { 50 | state.blogPhotoPreview = !state.blogPhotoPreview; 51 | }, 52 | toggleEditPost(state, payload) { 53 | state.editPost = payload; 54 | }, 55 | setBlogState(state, payload) { 56 | state.blogTitle = payload.blogTitle; 57 | state.blogHTML = payload.blogHTML; 58 | state.blogPhotoFileURL = payload.blogCoverPhoto; 59 | state.blogPhotoName = payload.blogCoverPhotoName; 60 | }, 61 | filterBlogPost(state, payload) { 62 | state.blogPosts = state.blogPosts.filter((post) => post.blogID !== payload); 63 | }, 64 | updateUser(state, payload) { 65 | state.user = payload; 66 | }, 67 | setProfileAdmin(state, payload) { 68 | state.profileAdmin = payload; 69 | console.log(state.profileAdmin); 70 | }, 71 | setProfileInfo(state, doc) { 72 | state.profileId = doc.id; 73 | state.profileEmail = doc.data().email; 74 | state.profileFirstName = doc.data().firstName; 75 | state.profileLastName = doc.data().lastName; 76 | state.profileUsername = doc.data().username; 77 | console.log(state.profileId); 78 | }, 79 | setProfileInitials(state) { 80 | state.profileInitials = 81 | state.profileFirstName.match(/(\b\S)?/g).join("") + state.profileLastName.match(/(\b\S)?/g).join(""); 82 | }, 83 | changeFirstName(state, payload) { 84 | state.profileFirstName = payload; 85 | }, 86 | changeLastName(state, payload) { 87 | state.profileLastName = payload; 88 | }, 89 | changeUsername(state, payload) { 90 | state.profileUsername = payload; 91 | }, 92 | }, 93 | actions: { 94 | async getCurrentUser({ commit }, user) { 95 | const dataBase = await db.collection("users").doc(firebase.auth().currentUser.uid); 96 | const dbResults = await dataBase.get(); 97 | commit("setProfileInfo", dbResults); 98 | commit("setProfileInitials"); 99 | const token = await user.getIdTokenResult(); 100 | const admin = await token.claims.admin; 101 | commit("setProfileAdmin", admin); 102 | }, 103 | async getPost({ state }) { 104 | const dataBase = await db.collection("blogPosts").orderBy("date", "desc"); 105 | const dbResults = await dataBase.get(); 106 | dbResults.forEach((doc) => { 107 | if (!state.blogPosts.some((post) => post.blogID === doc.id)) { 108 | const data = { 109 | blogID: doc.data().blogID, 110 | blogHTML: doc.data().blogHTML, 111 | blogCoverPhoto: doc.data().blogCoverPhoto, 112 | blogTitle: doc.data().blogTitle, 113 | blogDate: doc.data().date, 114 | blogCoverPhotoName: doc.data().blogCoverPhotoName, 115 | }; 116 | state.blogPosts.push(data); 117 | } 118 | }); 119 | state.postLoaded = true; 120 | }, 121 | async updatePost({ commit, dispatch }, payload) { 122 | commit("filterBlogPost", payload); 123 | await dispatch("getPost"); 124 | }, 125 | async deletePost({ commit }, payload) { 126 | const getPost = await db.collection("blogPosts").doc(payload); 127 | await getPost.delete(); 128 | commit("filterBlogPost", payload); 129 | }, 130 | async updateUserSettings({ commit, state }) { 131 | const dataBase = await db.collection("users").doc(state.profileId); 132 | await dataBase.update({ 133 | firstName: state.profileFirstName, 134 | lastName: state.profileLastName, 135 | username: state.profileUsername, 136 | }); 137 | commit("setProfileInitials"); 138 | }, 139 | }, 140 | modules: {}, 141 | }); 142 | -------------------------------------------------------------------------------- /src/views/Admin.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 37 | 38 | 95 | -------------------------------------------------------------------------------- /src/views/BlogPreview.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | 28 | 53 | -------------------------------------------------------------------------------- /src/views/Blogs.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 39 | 40 | 88 | -------------------------------------------------------------------------------- /src/views/CreatePost.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 168 | 169 | 307 | -------------------------------------------------------------------------------- /src/views/EditBlog.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 176 | 177 | 315 | -------------------------------------------------------------------------------- /src/views/ForgotPassword.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 72 | 73 | 89 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 53 | 54 | 98 | -------------------------------------------------------------------------------- /src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 68 | 69 | 183 | -------------------------------------------------------------------------------- /src/views/Profile.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 89 | 175 | -------------------------------------------------------------------------------- /src/views/Register.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 95 | 96 | 103 | -------------------------------------------------------------------------------- /src/views/ViewBlog.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 27 | 28 | 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chainWebpack: (config) => { 3 | const svgRule = config.module.rule("svg"); 4 | 5 | svgRule.uses.clear(); 6 | 7 | svgRule 8 | .use("babel-loader") 9 | .loader("babel-loader") 10 | .end() 11 | .use("vue-svg-loader") 12 | .loader("vue-svg-loader"); 13 | }, 14 | }; 15 | --------------------------------------------------------------------------------