mirror of
https://github.com/ClaytonWWilson/CS307-Team24.git
synced 2025-12-16 10:18:48 +00:00
Merge pull request #12 from ClaytonWWilson/user_subscription
Re-organized file structures
This commit is contained in:
commit
2d00090988
27
functions/handlers/post.js
Normal file
27
functions/handlers/post.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* eslint-disable promise/always-return */
|
||||
exports.putPost = (req, res) => {
|
||||
if (req.body.body.trim() === '') {
|
||||
return res.status(400).json({ body: 'Body must not be empty!'});
|
||||
}
|
||||
|
||||
const newPost = {
|
||||
body: req.body.body,
|
||||
userHandle: req.user.handle,
|
||||
userImage: req.user.imageUrl,
|
||||
createdAt: new Date().toISOString(),
|
||||
likeCount: 0,
|
||||
commentCount: 0
|
||||
};
|
||||
|
||||
db.collection('post').add(newPost)
|
||||
.then((doc) => {
|
||||
const resPost = newPost;
|
||||
resPost.postId = doc.id;
|
||||
res.json(resPost);
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ error: 'something is wrong'});
|
||||
console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
33
functions/handlers/users.js
Normal file
33
functions/handlers/users.js
Normal file
@ -0,0 +1,33 @@
|
||||
exports.getUserDetails = (req, res) => {
|
||||
let userData = {};
|
||||
db.doc('/users/${req.params.handle}').get().then((doc) => {
|
||||
if (doc.exists) {
|
||||
userData.user = doc.data();
|
||||
return db.collection('post').where('userHandle', '==', req.params.handle)
|
||||
.orderBy('createdAt', 'desc').get();
|
||||
} else {
|
||||
return res.status(404).json({
|
||||
error: 'User not found'
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((data) => {
|
||||
userData.posts = [];
|
||||
data.forEach((doc) => {
|
||||
userData.posts.push({
|
||||
body: doc.data().body,
|
||||
createAt: doc.data().createAt,
|
||||
userHandle: doc.data().userHandle,
|
||||
userImage: doc.data().userImage,
|
||||
likeCount: doc.data().likeCount,
|
||||
commentCount: doc.data().commentCount,
|
||||
postId: doc.id
|
||||
});
|
||||
});
|
||||
return res.json(userData);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
return res.status(500).json({ error: err.code});
|
||||
});
|
||||
};
|
||||
@ -1,78 +1,28 @@
|
||||
/* eslint-disable promise/always-return */
|
||||
const functions = require('firebase-functions');
|
||||
const admin = require('firebase-admin');
|
||||
const app = require('express')();
|
||||
admin.initializeApp();
|
||||
const db = admin.firestore();
|
||||
const FBauth = require('./util/fbAuth');
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyCvsWetg4qFdsPGfJ3LCw_QaaYzoan7Q34",
|
||||
authDomain: "twistter-e4649.firebaseapp.com",
|
||||
databaseURL: "https://twistter-e4649.firebaseio.com",
|
||||
projectId: "twistter-e4649",
|
||||
storageBucket: "twistter-e4649.appspot.com",
|
||||
messagingSenderId: "20131817365",
|
||||
appId: "1:20131817365:web:633c95fb08b16d4526b89c"
|
||||
};
|
||||
const cors = require('cors');
|
||||
app.use(cors());
|
||||
|
||||
const firebase = require('firebase');
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
const { db } = require('./util/admin');
|
||||
|
||||
// Acts as a middleman between the client and any function that you use it with
|
||||
// The function will only execute if the user is logged in, or rather, they have
|
||||
// a valid token
|
||||
const FBAuth = (req, resp, next) => {
|
||||
let idToken;
|
||||
const {
|
||||
putPost
|
||||
} = require('./handlers/post');
|
||||
|
||||
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
|
||||
idToken = req.headers.authorization.split('Bearer ')[1];
|
||||
} else {
|
||||
console.error('No token found');
|
||||
return resp.status(403).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
admin.auth().verifyIdToken(idToken)
|
||||
.then(decodedToken => {
|
||||
req.user = decodedToken;
|
||||
console.log(decodedToken);
|
||||
return db.collection('users')
|
||||
.where('userId', '==', req.user.uid)
|
||||
.limit(1)
|
||||
.get();
|
||||
})
|
||||
.then(data => {
|
||||
req.user.handle = data.docs[0].data().handle;
|
||||
return next();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error verifying token', err);
|
||||
return res.status(403).json(err);
|
||||
})
|
||||
}
|
||||
const {
|
||||
getUserDetails
|
||||
} = require('./handlers/users');
|
||||
|
||||
app.get('/getUsers', (req, res) => {
|
||||
admin.firestore().collection('users').get().then(data => {
|
||||
let users = [];
|
||||
data.forEach(doc => {
|
||||
users.push(doc.data());
|
||||
}); return res.json(users);
|
||||
}).catch((err) => console.error(err));
|
||||
});
|
||||
|
||||
app.post('/postUser', (req, res) => {
|
||||
const newUser = {
|
||||
body: req.body.body
|
||||
};
|
||||
admin.firestore().collection('users').add(newUser).then((doc) => {
|
||||
res.json({
|
||||
message: 'Successfully added!'
|
||||
});
|
||||
}).catch((err) => {
|
||||
res.status(500).json({
|
||||
error: "Error in posting user!"
|
||||
});
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
// post routes
|
||||
app.post('/putPost', FBauth, putPost);
|
||||
|
||||
// users routes
|
||||
app.get('/getUser/:handle', getUserDetails);
|
||||
|
||||
|
||||
exports.api = functions.https.onRequest(app);
|
||||
192
functions/package-lock.json
generated
192
functions/package-lock.json
generated
@ -24,16 +24,31 @@
|
||||
}
|
||||
},
|
||||
"@firebase/app": {
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.4.16.tgz",
|
||||
"integrity": "sha512-4aa6ixQlV6xQxj4HbwFKrfYZnnKk8AtB/vEEuIaBCGQYBvV287OVNCozXd4CC4Q4I4Vtkzrc+kggahYFl8nDWQ==",
|
||||
"version": "0.4.17",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.4.17.tgz",
|
||||
"integrity": "sha512-YkCe10/KHnfJ5Lx79SCQ4ZJRlpnwe8Yns6Ntf7kltXq1hCQCUrKEU3zaOTPY90SBx36hYm47IaqkKwT/kBOK3A==",
|
||||
"requires": {
|
||||
"@firebase/app-types": "0.4.3",
|
||||
"@firebase/logger": "0.1.24",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/logger": "0.1.25",
|
||||
"@firebase/util": "0.2.28",
|
||||
"dom-storage": "2.1.0",
|
||||
"tslib": "1.10.0",
|
||||
"xmlhttprequest": "1.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/logger": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||
},
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/app-types": {
|
||||
@ -75,17 +90,32 @@
|
||||
}
|
||||
},
|
||||
"@firebase/firestore": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.5.2.tgz",
|
||||
"integrity": "sha512-CPYLvkGZBKE47oQC9a0q13UMVRj3LvnSbB1nOerktE3CGRHKy44LxDumamN8Kj067hV/80mKK9FdbeUufwO/Rg==",
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.5.3.tgz",
|
||||
"integrity": "sha512-O/yAbXpitOA6g627cUl0/FHYlkTy1EiEKMKOlnlMOJF2fH+nLVZREXjsrCC7N2tIvTn7yYwfpZ4zpSNvrhwiTA==",
|
||||
"requires": {
|
||||
"@firebase/firestore-types": "1.5.0",
|
||||
"@firebase/logger": "0.1.24",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/logger": "0.1.25",
|
||||
"@firebase/util": "0.2.28",
|
||||
"@firebase/webchannel-wrapper": "0.2.26",
|
||||
"@grpc/proto-loader": "^0.5.0",
|
||||
"grpc": "1.23.3",
|
||||
"tslib": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/logger": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||
},
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/firestore-types": {
|
||||
@ -94,9 +124,9 @@
|
||||
"integrity": "sha512-VhRHNbEbak+R2iK8e1ir2Lec7eaHMZpGTRy6LMtzATYthlkwNHF9tO8JU8l6d1/kYkI4+DWzX++i3HhTziHEWA=="
|
||||
},
|
||||
"@firebase/functions": {
|
||||
"version": "0.4.17",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.17.tgz",
|
||||
"integrity": "sha512-heWMXrR3hgvQNe1JEZMUeY7a0QFLMVwVS+lzLq/lzk06bj22X9bJy7Yct+/P9P1ftnsCGLrhk3jAEuL78seoqg==",
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.18.tgz",
|
||||
"integrity": "sha512-N/ijwpxJy26kOErYIi5QS8pQgMZEuEMF/zDaNmgqcoN3J8P52NhBnVQZnIl+U4W96nQfNiURhSwXEERHFyvSZQ==",
|
||||
"requires": {
|
||||
"@firebase/functions-types": "0.3.8",
|
||||
"@firebase/messaging-types": "0.3.2",
|
||||
@ -110,14 +140,24 @@
|
||||
"integrity": "sha512-9hajHxA4UWVCGFmoL8PBYHpamE3JTNjObieMmnvZw3cMRTP2EwipMpzZi+GPbMlA/9swF9yHCY/XFAEkwbvdgQ=="
|
||||
},
|
||||
"@firebase/installations": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.2.6.tgz",
|
||||
"integrity": "sha512-hkuKmBtnsmqIfWxt9KyaN+cP574pfTcB81IG5tnmVcgP1xQ4hyQ9LRP0M7jDTGWMw272TInBzUuaM05xw9GMnA==",
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.2.7.tgz",
|
||||
"integrity": "sha512-67tzowHVwRBtEuB1HLMD+fCdoRyinOQlMKBes7UwrtZIVd0CPDUqAKxNqup5EypWZb7O2tqFtRzK7POajfSNMA==",
|
||||
"requires": {
|
||||
"@firebase/installations-types": "0.1.2",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/util": "0.2.28",
|
||||
"idb": "3.0.2",
|
||||
"tslib": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/installations-types": {
|
||||
@ -131,13 +171,23 @@
|
||||
"integrity": "sha512-wPwhWCepEjWiTIqeC9U+7Hcw4XwezKPdXmyXbYSPiWNDcVekNgMPkntwSK+/2ufJO/1nMwAL2n6fL12oQG/PpQ=="
|
||||
},
|
||||
"@firebase/messaging": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.4.10.tgz",
|
||||
"integrity": "sha512-WqtSqlulV2ix4MZ3r1HwGAEj0DiEWtpNCSPh5wOXZsj8Kd01Q2QPTLUtUWmwXSV9WCQWnowfE2x8wjq5388ixw==",
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.4.11.tgz",
|
||||
"integrity": "sha512-KYt479yio6ThkV7Pb9LRB1KPIBio+OR4RozwyoLC1ZSVQdTIrd/sVEuDSzYY88Wh/6Kg6ejdu2z6mfWG9l1ZaQ==",
|
||||
"requires": {
|
||||
"@firebase/messaging-types": "0.3.2",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/util": "0.2.28",
|
||||
"tslib": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/messaging-types": {
|
||||
@ -146,15 +196,30 @@
|
||||
"integrity": "sha512-2qa2qNKqpalmtwaUV3+wQqfCm5myP/dViIBv+pXF8HinemIfO1IPQtr9pCNfsSYyus78qEhtfldnPWXxUH5v0w=="
|
||||
},
|
||||
"@firebase/performance": {
|
||||
"version": "0.2.18",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.2.18.tgz",
|
||||
"integrity": "sha512-PcN+nTPaMGqODfwAXgwbaCvcxXH+YzvK6UpZzm0Bl9wmW28/oJipnUxF3cYbVGCiaLAaByIPVSIF22XhTOjUtA==",
|
||||
"version": "0.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.2.19.tgz",
|
||||
"integrity": "sha512-dINWwR/XcSiSnFNNX7QWfec8bymiXk1Zp6mPyPN+R9ONMrpDbygQUy06oT/6r/xx9nHG4Za6KMUJag3sWNKqnQ==",
|
||||
"requires": {
|
||||
"@firebase/installations": "0.2.6",
|
||||
"@firebase/logger": "0.1.24",
|
||||
"@firebase/installations": "0.2.7",
|
||||
"@firebase/logger": "0.1.25",
|
||||
"@firebase/performance-types": "0.0.3",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/util": "0.2.28",
|
||||
"tslib": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/logger": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||
},
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/performance-types": {
|
||||
@ -163,9 +228,9 @@
|
||||
"integrity": "sha512-RuC63nYJPJU65AsrNMc3fTRcRgHiyNcQLh9ufeKUT1mEsFgpxr167gMb+tpzNU4jsbvM6+c6nQAFdHpqcGkRlQ=="
|
||||
},
|
||||
"@firebase/polyfill": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.21.tgz",
|
||||
"integrity": "sha512-2mqS3FQHMhCGyfMGRsaZEypHSBD8hVmp9ZBnZSkn8hq5sSOLiNTFSC0FsvNu5z99GNsPQJFTui8bxcZl5cHQbw==",
|
||||
"version": "0.3.22",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.22.tgz",
|
||||
"integrity": "sha512-PYbEqDHJhJJoF2Q5IB/oP0Tz6O2vSUPtODy9kUQibi+T0bK1gkTaySPwz8GAgHfIpFNENj1kK+7Xpf87R8bYbw==",
|
||||
"requires": {
|
||||
"core-js": "3.2.1",
|
||||
"promise-polyfill": "8.1.3",
|
||||
@ -180,13 +245,23 @@
|
||||
}
|
||||
},
|
||||
"@firebase/storage": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.11.tgz",
|
||||
"integrity": "sha512-Q2ffXE+X62gFy5mZkg7qhzAC7+kqaNZWpgS+297h/hWr/cFBDyC8eBPmnI509eKi2okixmOMbWnNluZkNYNSfw==",
|
||||
"version": "0.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.12.tgz",
|
||||
"integrity": "sha512-8hXt3qPZlVH+yPF4W9Dc15/gBiTPGUJUgYs3dH9WnO41QWl1o4aNlZpZK/pdnpCIO1GmN0+PxJW9TCNb0H0Hqw==",
|
||||
"requires": {
|
||||
"@firebase/storage-types": "0.3.3",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/util": "0.2.28",
|
||||
"tslib": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@firebase/storage-types": {
|
||||
@ -1396,35 +1471,48 @@
|
||||
}
|
||||
},
|
||||
"firebase": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/firebase/-/firebase-6.6.1.tgz",
|
||||
"integrity": "sha512-iXbHPIBRt04xYSjWffnARqZbc3vUc0RTnOHsMtAqaT7pqDWicaghEwj2WbCJ0+JLAiKnLNK7fTjW73zfKQSSoQ==",
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/firebase/-/firebase-6.6.2.tgz",
|
||||
"integrity": "sha512-uL9uNbutC0T8GAxrGgOCC35Ven3QKJqzJozNoVIpBuiWrB9ifm9aKOxn44h6o5ouviax3LVvoiG2jLkLkdQq4A==",
|
||||
"requires": {
|
||||
"@firebase/app": "0.4.16",
|
||||
"@firebase/app": "0.4.17",
|
||||
"@firebase/app-types": "0.4.3",
|
||||
"@firebase/auth": "0.12.0",
|
||||
"@firebase/database": "0.5.3",
|
||||
"@firebase/firestore": "1.5.2",
|
||||
"@firebase/functions": "0.4.17",
|
||||
"@firebase/installations": "0.2.6",
|
||||
"@firebase/messaging": "0.4.10",
|
||||
"@firebase/performance": "0.2.18",
|
||||
"@firebase/polyfill": "0.3.21",
|
||||
"@firebase/storage": "0.3.11",
|
||||
"@firebase/util": "0.2.27"
|
||||
"@firebase/database": "0.5.4",
|
||||
"@firebase/firestore": "1.5.3",
|
||||
"@firebase/functions": "0.4.18",
|
||||
"@firebase/installations": "0.2.7",
|
||||
"@firebase/messaging": "0.4.11",
|
||||
"@firebase/performance": "0.2.19",
|
||||
"@firebase/polyfill": "0.3.22",
|
||||
"@firebase/storage": "0.3.12",
|
||||
"@firebase/util": "0.2.28"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/database": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.3.tgz",
|
||||
"integrity": "sha512-TFjQ/M0T4jO24jAMU5cZAHNk3ndNfeNtGKe5PL4o/YrGYJHg3XaE2LKzU/vFrXUFLnLxqbETzXjFa4hTA6cDUg==",
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.4.tgz",
|
||||
"integrity": "sha512-Hz1Bi3fzIcNNocE4EhvvwoEQGurG2BGssWD3/6a2bzty+K1e57SLea2Ied8QYNBUU1zt/4McHfa3Y71EQIyn/w==",
|
||||
"requires": {
|
||||
"@firebase/database-types": "0.4.3",
|
||||
"@firebase/logger": "0.1.24",
|
||||
"@firebase/util": "0.2.27",
|
||||
"@firebase/logger": "0.1.25",
|
||||
"@firebase/util": "0.2.28",
|
||||
"faye-websocket": "0.11.3",
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
},
|
||||
"@firebase/logger": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||
},
|
||||
"@firebase/util": {
|
||||
"version": "0.2.28",
|
||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||
"requires": {
|
||||
"tslib": "1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
"node": "8"
|
||||
},
|
||||
"dependencies": {
|
||||
"firebase": "^6.6.1",
|
||||
"firebase": "^6.6.2",
|
||||
"firebase-admin": "^8.0.0",
|
||||
"firebase-functions": "^3.1.0"
|
||||
},
|
||||
|
||||
7
functions/util/admin.js
Normal file
7
functions/util/admin.js
Normal file
@ -0,0 +1,7 @@
|
||||
const admin = require('firebase-admin');
|
||||
|
||||
admin.initializeApp();
|
||||
|
||||
const db = admin.firestore();
|
||||
|
||||
module.exports = { admin, db };
|
||||
9
functions/util/config.js
Normal file
9
functions/util/config.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
apiKey: "AIzaSyCvsWetg4qFdsPGfJ3LCw_QaaYzoan7Q34",
|
||||
authDomain: "twistter-e4649.firebaseapp.com",
|
||||
databaseURL: "https://twistter-e4649.firebaseio.com",
|
||||
projectId: "twistter-e4649",
|
||||
storageBucket: "twistter-e4649.appspot.com",
|
||||
messagingSenderId: "20131817365",
|
||||
appId: "1:20131817365:web:633c95fb08b16d4526b89c"
|
||||
};
|
||||
28
functions/util/fbAuth.js
Normal file
28
functions/util/fbAuth.js
Normal file
@ -0,0 +1,28 @@
|
||||
const { admin, db } = require('./admin');
|
||||
|
||||
module.exports = (req, res, next) => {
|
||||
let idToken;
|
||||
if (req.headers.authorization) {
|
||||
idToken = req.headers.authorization;
|
||||
} else {
|
||||
console.error('No token found');
|
||||
return res.status(403).json({ error: 'Unauthorized'});
|
||||
}
|
||||
|
||||
admin.auth().verifyIdToken(idToken)
|
||||
.then((decodedToken) => {
|
||||
req.user = decodedToken;
|
||||
return db.collection('users').where('userId', '==', req.user.uid)
|
||||
.limit(1)
|
||||
.get();
|
||||
})
|
||||
.then((data) => {
|
||||
req.user.handle = data.docs[0].data().handle;
|
||||
req.user.imageUrl = data.docs[0].data().imageUrl;
|
||||
return next();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error while verifying token ', err);
|
||||
return res.status(403).json(err);
|
||||
});
|
||||
};
|
||||
0
functions/util/validator.js
Normal file
0
functions/util/validator.js
Normal file
@ -1,78 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Welcome to Firebase Hosting</title>
|
||||
|
||||
<!-- update the version number as needed -->
|
||||
<script defer src="/__/firebase/6.6.0/firebase-app.js"></script>
|
||||
<!-- include only the Firebase features as you need -->
|
||||
<script defer src="/__/firebase/6.6.0/firebase-auth.js"></script>
|
||||
<script defer src="/__/firebase/6.6.0/firebase-database.js"></script>
|
||||
<script defer src="/__/firebase/6.6.0/firebase-messaging.js"></script>
|
||||
<script defer src="/__/firebase/6.6.0/firebase-storage.js"></script>
|
||||
<!-- initialize the SDK after all desired features are loaded -->
|
||||
<script defer src="/__/firebase/init.js"></script>
|
||||
|
||||
<style media="screen">
|
||||
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
|
||||
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; }
|
||||
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
|
||||
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
|
||||
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
|
||||
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
|
||||
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
|
||||
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
|
||||
@media (max-width: 600px) {
|
||||
body, #message { margin-top: 0; background: white; box-shadow: none; }
|
||||
body { border-top: 16px solid #ffa100; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
<h2>This is a test message!</h2>
|
||||
<h2>Welcome</h2>
|
||||
|
||||
|
||||
<h1>Firebase Hosting Setup Complete</h1>
|
||||
<p>You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!</p>
|
||||
<a target="_blank" href="https://firebase.google.com/docs/hosting/">Open Hosting Documentation</a>
|
||||
<div id="like_button_container"></div>
|
||||
</div>
|
||||
<p id="load">Firebase SDK Loading…</p>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
||||
// // The Firebase SDK is initialized and available here!
|
||||
//
|
||||
// firebase.auth().onAuthStateChanged(user => { });
|
||||
// firebase.database().ref('/path/to/ref').on('value', snapshot => { });
|
||||
// firebase.messaging().requestPermission().then(() => { });
|
||||
// firebase.storage().ref('/path/to/ref').getDownloadURL().then(() => { });
|
||||
//
|
||||
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
||||
|
||||
try {
|
||||
let app = firebase.app();
|
||||
let features = ['auth', 'database', 'messaging', 'storage'].filter(feature => typeof app[feature] === 'function');
|
||||
document.getElementById('load').innerHTML = `Firebase SDK loaded with ${features.join(', ')}`;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
document.getElementById('load').innerHTML = 'Error loading the Firebase SDK, check the console.';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Load React. -->
|
||||
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
|
||||
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
|
||||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
|
||||
|
||||
<!-- Load our React component. -->
|
||||
<script src="like_button.js"></script>
|
||||
<script src="loader.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,30 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const e = React.createElement;
|
||||
|
||||
class LikeButton extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
liked: false
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.liked) {
|
||||
return 'You liked this.';
|
||||
}
|
||||
|
||||
return e(
|
||||
'button', {
|
||||
onClick: () => this.setState({
|
||||
liked: true
|
||||
})
|
||||
},
|
||||
'Like'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const domContainer = document.querySelector('#like_button_container');
|
||||
ReactDOM.render(e(LikeButton), domContainer);
|
||||
14930
twistter-frontend/package-lock.json
generated
14930
twistter-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,16 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.4.3",
|
||||
"axios": "^0.19.0",
|
||||
"create-react-app": "^3.1.2",
|
||||
"install": "^0.13.0",
|
||||
"node-pre-gyp": "^0.13.0",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-scripts": "^3.1.2"
|
||||
"react-redux": "^7.1.1",
|
||||
"react-router-dom": "^5.1.0",
|
||||
"react-scripts": "0.9.5",
|
||||
"redux": "^4.0.4",
|
||||
"redux-thunk": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
@ -16,18 +21,5 @@
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"proxy": "https://us-central1-socialape-2619.cloudfunctions.net/api"
|
||||
}
|
||||
}
|
||||
|
||||
0
twistter-frontend/redux/actions/dataActions.js
Normal file
0
twistter-frontend/redux/actions/dataActions.js
Normal file
0
twistter-frontend/redux/actions/userActions.js
Normal file
0
twistter-frontend/redux/actions/userActions.js
Normal file
0
twistter-frontend/redux/reducers/dataReducer.js
Normal file
0
twistter-frontend/redux/reducers/dataReducer.js
Normal file
0
twistter-frontend/redux/reducers/uiReducer.js
Normal file
0
twistter-frontend/redux/reducers/uiReducer.js
Normal file
0
twistter-frontend/redux/reducers/userReducer.js
Normal file
0
twistter-frontend/redux/reducers/userReducer.js
Normal file
18
twistter-frontend/redux/store.js
Normal file
18
twistter-frontend/redux/store.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import userReducer from './reducers/userReducer';
|
||||
import dataReducer from './reducers/dataReducer';
|
||||
import uiReducer from './reducers/uiReducer';
|
||||
|
||||
const initialState = {};
|
||||
|
||||
const middleware = {thunk};
|
||||
|
||||
const reducers = combineReducers({
|
||||
user: userReducer,
|
||||
data: dataReducer,
|
||||
UI: uiReducer
|
||||
});
|
||||
|
||||
//const store = createStore(reducers, )
|
||||
0
twistter-frontend/redux/types.js
Normal file
0
twistter-frontend/redux/types.js
Normal file
@ -37,4 +37,12 @@
|
||||
.authInput {
|
||||
background-color: #eee;
|
||||
width:500px;
|
||||
height:40px;
|
||||
border: 0px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 80px auto 0 auto;
|
||||
max-width: 1200px;
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
/* eslint-disable */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import './App.css';
|
||||
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import Route from 'react-router-dom/Route';
|
||||
|
||||
|
||||
import home from './Home.js';
|
||||
import register from './Register.js';
|
||||
import login from './Login.js';
|
||||
@ -13,10 +16,12 @@ class App extends Component {
|
||||
return (
|
||||
<Router>
|
||||
|
||||
|
||||
<div className="app">
|
||||
<Route exact path="/" component={home}/>
|
||||
<Route exact path="/register" component={register}/>
|
||||
<Route exact path="/login" component={login}/>
|
||||
<Route exact path="/user" component={user}/>
|
||||
</div>
|
||||
|
||||
</Router>
|
||||
|
||||
31
twistter-frontend/src/components/layout/NavBar.js
Normal file
31
twistter-frontend/src/components/layout/NavBar.js
Normal file
@ -0,0 +1,31 @@
|
||||
/* eslint-disable */
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import ToolBar from '@material-ui/core/Toolbar';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
export class Navbar extends Component {
|
||||
render() {
|
||||
return (
|
||||
<AppBar>
|
||||
<ToolBar>
|
||||
<Button component={ Link } to='/user'>
|
||||
User
|
||||
</Button>
|
||||
<Button component={ Link } to='/login'>
|
||||
Login
|
||||
</Button>
|
||||
<Button component={ Link } to='/register'>
|
||||
Register
|
||||
</Button>
|
||||
<Button component={ Link } to='/'>
|
||||
Home
|
||||
</Button>
|
||||
</ToolBar>
|
||||
</AppBar>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Navbar;
|
||||
52
twistter-frontend/src/components/topic/ChipsArray.js
Normal file
52
twistter-frontend/src/components/topic/ChipsArray.js
Normal file
@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flexWrap: 'wrap',
|
||||
padding: theme.spacing(0.5),
|
||||
},
|
||||
chip: {
|
||||
margin: theme.spacing(0.5),
|
||||
},
|
||||
}));
|
||||
|
||||
export default function ChipsArray() {
|
||||
const classes = useStyles();
|
||||
const [chipData, setChipData] = React.useState([
|
||||
{ key: 0, label: 'Angular' },
|
||||
{ key: 1, label: 'jQuery' },
|
||||
{ key: 2, label: 'Polymer' },
|
||||
{ key: 3, label: 'React' },
|
||||
{ key: 4, label: 'Vue.js' },
|
||||
]);
|
||||
|
||||
const handleDelete = chipToDelete => () => {
|
||||
if (chipToDelete.label === 'React') {
|
||||
alert('Why would you want to delete React?! :)');
|
||||
return;
|
||||
}
|
||||
|
||||
setChipData(chips => chips.filter(chip => chip.key !== chipToDelete.key));
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper className={classes.root}>
|
||||
{chipData.map(data => {
|
||||
|
||||
return (
|
||||
<Chip
|
||||
key={data.key}
|
||||
label={data.label}
|
||||
onDelete={handleDelete(data)}
|
||||
className={classes.chip}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
BIN
twistter-frontend/src/images/no-img.png
Normal file
BIN
twistter-frontend/src/images/no-img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
40
twistter-frontend/src/pages/user.js
Normal file
40
twistter-frontend/src/pages/user.js
Normal file
@ -0,0 +1,40 @@
|
||||
/* eslint-disable */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import StaticProfile from '../components/profile/StaticProfile';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
import PostSkeleton from '../util/PostSkeleton';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
||||
class user extends Component {
|
||||
render() {
|
||||
const postMarkup = PostSkeleton;
|
||||
|
||||
return (
|
||||
<b>User page</b>
|
||||
// <Grid container spacing={16}>
|
||||
// <Grid item sm={8} xs={12}>
|
||||
// <b>postMarkup</b>
|
||||
// {postMarkup}
|
||||
// </Grid>
|
||||
// {/* <Grid item sm={4} xs={12}>
|
||||
// <StaticProfile profile={this.state.profile} />
|
||||
// </Grid> */}
|
||||
// </Grid>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
user.propTypes = {
|
||||
// getUserData: PropTypes.func.isRequired,
|
||||
//data: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
data: state.data
|
||||
});
|
||||
|
||||
export default connect(user);
|
||||
77
twistter-frontend/src/util/PostSkeleton.js
Normal file
77
twistter-frontend/src/util/PostSkeleton.js
Normal file
@ -0,0 +1,77 @@
|
||||
/* eslint-disable */
|
||||
import React, { Fragment } from 'react';
|
||||
import NoImg from '../images/no-img.png';
|
||||
import PropTypes from 'prop-types';
|
||||
// MUI
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
|
||||
import withStyles from '@material-ui/core/styles/withStyles';
|
||||
|
||||
const styles = (theme) => ({
|
||||
...theme,
|
||||
card: {
|
||||
display: 'flex',
|
||||
marginBottom: 20
|
||||
},
|
||||
cardContent: {
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
padding: 25
|
||||
},
|
||||
cover: {
|
||||
minWidth: 200,
|
||||
objectFit: 'cover'
|
||||
},
|
||||
handle: {
|
||||
width: 60,
|
||||
height: 18,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
marginBottom: 7
|
||||
},
|
||||
date: {
|
||||
height: 14,
|
||||
width: 100,
|
||||
backgroundColor: 'rgba(0,0,0, 0.3)',
|
||||
marginBottom: 10
|
||||
},
|
||||
fullLine: {
|
||||
height: 15,
|
||||
width: '90%',
|
||||
backgroundColor: 'rgba(0,0,0, 0.6)',
|
||||
marginBottom: 10
|
||||
},
|
||||
halfLine: {
|
||||
height: 15,
|
||||
width: '50%',
|
||||
backgroundColor: 'rgba(0,0,0, 0.6)',
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
const PostSkeleton = (props) => {
|
||||
const { classes } = props;
|
||||
|
||||
const content = Array.from({ length: 5 }).map((item, index) => (
|
||||
<Card className={classes.card} key={index}>
|
||||
<CardMedia className={classes.cover} image={NoImg} />
|
||||
<CardContent className={classes.cardContent}>
|
||||
<div className={classes.handle} />
|
||||
<div className={classes.date} />
|
||||
<div className={classes.fullLine} />
|
||||
<div className={classes.fullLine} />
|
||||
<div className={classes.halfLine} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
));
|
||||
|
||||
return <Fragment>{content}</Fragment>;
|
||||
};
|
||||
|
||||
PostSkeleton.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default withStyles(styles)(PostSkeleton);
|
||||
|
||||
64
twistter-frontend/src/util/ProfileSkeleton.js
Normal file
64
twistter-frontend/src/util/ProfileSkeleton.js
Normal file
@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import withStyles from '@material-ui/core/styles/withStyles';
|
||||
import NoImg from '../images/no-img.png';
|
||||
// MUI
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
// Icons
|
||||
import LocationOn from '@material-ui/icons/LocationOn';
|
||||
import LinkIcon from '@material-ui/icons/Link';
|
||||
import CalendarToday from '@material-ui/icons/CalendarToday';
|
||||
|
||||
const styles = (theme) => ({
|
||||
...theme,
|
||||
handle: {
|
||||
height: 20,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
width: 60,
|
||||
margin: '0 auto 7px auto'
|
||||
},
|
||||
fullLine: {
|
||||
height: 15,
|
||||
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||
width: '100%',
|
||||
marginBottom: 10
|
||||
},
|
||||
halfLine: {
|
||||
height: 15,
|
||||
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||
width: '50%',
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
const ProfileSkeleton = (props) => {
|
||||
const { classes } = props;
|
||||
return (
|
||||
<Paper className={classes.paper}>
|
||||
<div className={classes.profile}>
|
||||
<div className="image-wrapper">
|
||||
<img src={NoImg} alt="profile" className="profile-image" />
|
||||
</div>
|
||||
<hr />
|
||||
<div className="profile-details">
|
||||
<div className={classes.handle} />
|
||||
<hr />
|
||||
<div className={classes.fullLine} />
|
||||
<div className={classes.fullLine} />
|
||||
<hr />
|
||||
<LocationOn color="primary" /> <span>Location</span>
|
||||
<hr />
|
||||
<LinkIcon color="primary" /> https://website.com
|
||||
<hr />
|
||||
<CalendarToday color="primary" /> Joined date
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
ProfileSkeleton.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ProfileSkeleton);
|
||||
Loading…
Reference in New Issue
Block a user