├── .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 |
2 |
9 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
![]()
12 |
13 |
{{ post.blogTitle }}
14 |
Posted on: {{ new Date(post.blogDate).toLocaleString("en-us", { dateStyle: "long" }) }}
15 |
16 | View The Post
17 |
18 |
19 |
20 |
21 |
22 |
49 |
50 |
157 |
--------------------------------------------------------------------------------
/src/components/BlogCoverPreview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
8 |
9 |
10 |
28 |
29 |
73 |
--------------------------------------------------------------------------------
/src/components/BlogPost.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ post.title }}
6 |
{{ post.blogTitle }}
7 |
{{ post.blogPost }}
8 |
9 |
10 | Login/Register
11 |
12 |
13 | View The Post
14 |
15 |
16 |
17 |
18 |
![]()
19 |
![]()
20 |
21 |
22 |
23 |
24 |
39 |
40 |
155 |
--------------------------------------------------------------------------------
/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
36 |
37 |
38 |
63 |
64 |
182 |
--------------------------------------------------------------------------------
/src/components/Loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
42 |
--------------------------------------------------------------------------------
/src/components/Modal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ this.modalMessage }}
5 |
6 |
7 |
8 |
9 |
10 |
20 |
21 |
52 |
--------------------------------------------------------------------------------
/src/components/Navigation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
48 |
49 |
50 | Home
51 | Blogs
52 | Create Post
53 | Login/Register
54 |
55 |
56 |
57 |
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 |
2 |
3 |
4 |
Administration
5 |
6 |
Add Admin
7 |
8 |
9 |
10 |
{{ this.functionMsg }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
37 |
38 |
95 |
--------------------------------------------------------------------------------
/src/views/BlogPreview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ this.blogTitle }}
5 |
![]()
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
53 |
--------------------------------------------------------------------------------
/src/views/Blogs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Toggle Editing Post
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
39 |
40 |
88 |
--------------------------------------------------------------------------------
/src/views/CreatePost.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Error:{{ this.errorMsg }}
8 |
9 |
20 |
21 |
22 |
23 |
24 |
25 | Post Preview
26 |
27 |
28 |
29 |
30 |
31 |
168 |
169 |
307 |
--------------------------------------------------------------------------------
/src/views/EditBlog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Error:{{ this.errorMsg }}
8 |
9 |
20 |
21 |
22 |
23 |
24 |
25 | Preview Changes
26 |
27 |
28 |
29 |
30 |
31 |
176 |
177 |
315 |
--------------------------------------------------------------------------------
/src/views/ForgotPassword.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
72 |
73 |
89 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
View More Recent Blogs
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
never miss a post. Register for your free account today!
16 |
Register for FireBlogs
17 |
18 |
19 |
20 |
21 |
22 |
53 |
54 |
98 |
--------------------------------------------------------------------------------
/src/views/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
30 |
68 |
69 |
183 |
--------------------------------------------------------------------------------
/src/views/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Account Settings
6 |
7 |
{{ $store.state.profileInitials }}
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
89 |
175 |
--------------------------------------------------------------------------------
/src/views/Register.vue:
--------------------------------------------------------------------------------
1 |
2 |
37 |
38 |
39 |
95 |
96 |
103 |
--------------------------------------------------------------------------------
/src/views/ViewBlog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ this.currentBlog[0].blogTitle }}
5 |
Posted on: {{ new Date(this.currentBlog[0].blogDate).toLocaleString("en-us", { dateStyle: "long" }) }}
6 |
![]()
7 |
8 |
9 |
10 |
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 |
--------------------------------------------------------------------------------