├── server
├── controller
│ ├── feedController.js
│ ├── loginController.js
│ ├── requestController.js
│ └── answersControllers.js
├── router
│ ├── feedRouter.js
│ ├── loginRouter.js
│ ├── requestRouter.js
│ └── answersRouter.js
├── model
│ └── model.js
└── server.js
├── .gitignore
├── README.md
├── client
├── assets
│ ├── icon.png
│ ├── favicon.png
│ └── splash.png
├── babel.config.js
├── .gitignore
├── routes
│ ├── Drawer.js
│ └── HomeStack.js
├── App.js
├── components
│ ├── Home.js
│ ├── CreateList.js
│ ├── CreateInput.js
│ ├── SendFeedback.js
│ └── CreateFeedback.js
├── app.json
├── shared
│ └── Header.js
└── package.json
├── package.json
└── LICENSE
/server/controller/feedController.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/controller/loginController.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/controller/requestController.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 | .env
--------------------------------------------------------------------------------
/server/controller/answersControllers.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # critique
2 |
3 | Ask for feedback, send feedback, receive feedback
--------------------------------------------------------------------------------
/client/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VNguyenCode/critique/HEAD/client/assets/icon.png
--------------------------------------------------------------------------------
/client/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VNguyenCode/critique/HEAD/client/assets/favicon.png
--------------------------------------------------------------------------------
/client/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VNguyenCode/critique/HEAD/client/assets/splash.png
--------------------------------------------------------------------------------
/client/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/server/router/feedRouter.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const feedRouter = express.Router();
3 |
4 | feedRouter.get();
5 |
6 | feedRouter.delete();
7 |
8 | module.exports = feedRouter;
--------------------------------------------------------------------------------
/server/router/loginRouter.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const loginRouter = express.Router()
3 |
4 | // handles user authenticaion from login page
5 |
6 | module.exports = loginRouter;
--------------------------------------------------------------------------------
/server/router/requestRouter.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const requestRouter = express.Router();
3 |
4 | // get request pulling down user feed
5 |
6 | module.exports = requestRouter;
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/server/router/answersRouter.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const answersRouter = express.Router();
3 |
4 | // get request pulling down user feed
5 | answersRouter.get()
6 |
7 | // posting feedback response to database
8 | answersRouter.post()
9 |
10 |
11 | module.exports = answersRouter;
--------------------------------------------------------------------------------
/client/routes/Drawer.js:
--------------------------------------------------------------------------------
1 | import {createDrawerNavigator} from 'react-navigation-drawer'
2 | import {createAppContainer} from 'react-navigation'
3 | import HomeStack from './HomeStack'
4 |
5 | const RootDrawerNavigator = createDrawerNavigator({
6 | Home: {
7 | screen: HomeStack
8 | }
9 | })
10 |
11 | export default createAppContainer(RootDrawerNavigator)
--------------------------------------------------------------------------------
/client/App.js:
--------------------------------------------------------------------------------
1 | import { StatusBar } from 'expo-status-bar';
2 | import React from 'react';
3 | import { StyleSheet, Text, View } from 'react-native';
4 | import Home from './components/Home';
5 | import Navigator from './routes/Drawer'
6 |
7 | export default function App() {
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | const styles = StyleSheet.create({
16 | container: {
17 | flex: 1,
18 | backgroundColor: '#FFF',
19 | marginTop:30
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/client/components/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { StyleSheet, View, Text, Button } from 'react-native';
3 |
4 | export default function Home({navigation}) {
5 |
6 | const pressHandler = () => {
7 | navigation.push('CreateFeedback')
8 | }
9 |
10 | return (
11 |
12 | Home Screen
13 |
17 | );
18 | }
19 |
20 | const styles = StyleSheet.create({
21 | container: {
22 | padding: 24,
23 | },
24 | });
--------------------------------------------------------------------------------
/client/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Critique",
4 | "slug": "Critique",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "web": {
23 | "favicon": "./assets/favicon.png"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/client/components/CreateList.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import { StyleSheet, View, Text, Button, Animated, TouchableHighlight, TouchableOpacity, StatusBar } from 'react-native';
3 | import { FlatList} from 'react-native-gesture-handler';
4 | import {SwipeListView} from 'react-native-swipe-list-view'
5 |
6 |
7 | export default function CreateList({item, pressHandler}){
8 |
9 | return (
10 | pressHandler(item.id)}>
11 | {item.text}
12 |
13 | )
14 | }
15 |
16 | const styles = StyleSheet.create({
17 | item: {
18 | padding:16,
19 | marginTop:16,
20 | borderColor: '#bbb',
21 | borderWidth: 1,
22 | borderStyle: 'dashed',
23 | borderRadius: 10
24 | }
25 | })
--------------------------------------------------------------------------------
/client/components/CreateInput.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import {StyleSheet, Text, TextInput, Button, View} from 'react-native'
3 |
4 | export default function AddTodo({submitHandler}){
5 | const [text,setText] = useState('')
6 |
7 | const changeHandler = (val) => {
8 | setText(val)
9 | }
10 |
11 | return (
12 |
13 |
17 |
19 | )
20 | }
21 |
22 | const styles = StyleSheet.create({
23 | input:{
24 | marginBottom:10,
25 | paddingHorizontal:8,
26 | paddingVertical: 6,
27 | borderBottomWidth:1,
28 | borderBottomColor: '#ddd'
29 | }
30 | })
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "critique",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node server/server.js",
9 | "start-dev": "nodemon server/server"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/critique38/critique.git"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "bugs": {
19 | "url": "https://github.com/critque38/critique/issues"
20 | },
21 | "homepage": "https://github.com/critique38/critique#readme",
22 | "dependencies": {
23 | "dotenv": "^8.2.0",
24 | "express": "^4.17.1",
25 | "pg": "^8.4.2"
26 | },
27 | "devDependencies": {
28 | "nodemon": "^2.0.6"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client/components/SendFeedback.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import { StyleSheet, View, Text, Button, Share } from 'react-native';
3 |
4 | export default function SendFeedback({navigation}) {
5 |
6 | const [link, setLink] = useState('www.google.com')
7 |
8 | const pressBack = () => {
9 | navigation.pop();
10 | }
11 |
12 | const onShare = () => {
13 |
14 | Share.share({
15 | message:link,
16 | title:'google.com'
17 | })
18 |
19 | }
20 |
21 | return (
22 |
23 | This is your generated link below:
24 | {link}
25 |
28 |
29 | );
30 | }
31 |
32 | const styles = StyleSheet.create({
33 | container: {
34 | padding: 24,
35 | },
36 | });
--------------------------------------------------------------------------------
/client/routes/HomeStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation-stack';
2 | import {createAppContainer} from 'react-navigation'
3 | import React from 'react';
4 | import Home from '../components/Home'
5 | import SendFeedback from '../components/SendFeedback';
6 | import CreateFeedback from '../components/CreateFeedback';
7 | import Header from '../shared/Header'
8 |
9 | const screens = {
10 | Home: {
11 | screen: Home,
12 | navigationOptions : ({navigation}) => {
13 | return {
14 | headerTitle: () => ,
15 | }
16 | }
17 | },
18 | CreateFeedback: {
19 | screen: CreateFeedback,
20 | },
21 | SendFeedback:{
22 | screen:SendFeedback,
23 | }
24 | };
25 |
26 | // home stack navigator screens
27 | const HomeStack = createStackNavigator(screens, {
28 | defaultNavigationOptions:{
29 | headerBackTitle:'Back',
30 | title: 'Critique',
31 | headerStyle : {
32 | backgroundColor: '#eee'
33 | },
34 | }
35 | });
36 |
37 | export default HomeStack;
--------------------------------------------------------------------------------
/client/shared/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {StyleSheet, Text, View } from 'react-native';
3 | import { MaterialIcons } from '@expo/vector-icons'
4 |
5 | export default function Header ({navigation}){
6 |
7 | const openMenu = () => {
8 | navigation.openDrawer()
9 | }
10 |
11 | return (
12 |
13 |
19 |
20 |
21 | Critique
22 |
23 |
24 |
25 | )
26 | }
27 |
28 | const styles = StyleSheet.create({
29 | header: {
30 | width: '100%',
31 | height: '100%',
32 | flexDirection: 'row',
33 | alignItems: 'center',
34 | justifyContent: 'center',
35 | },
36 | headerText: {
37 | fontWeight:'bold',
38 | fontSize: 20,
39 | color: '#333'
40 | },
41 | icon:{
42 | position:'absolute',
43 | left:-50
44 | }
45 | })
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@react-native-community/masked-view": "0.1.10",
12 | "expo": "~39.0.2",
13 | "expo-status-bar": "~1.0.2",
14 | "react": "16.13.1",
15 | "react-dom": "16.13.1",
16 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.4.tar.gz",
17 | "react-native-gesture-handler": "~1.7.0",
18 | "react-native-reanimated": "~1.13.0",
19 | "react-native-safe-area-context": "3.1.4",
20 | "react-native-screens": "~2.10.1",
21 | "react-native-share": "^4.0.4",
22 | "react-native-swipe-list-view": "^3.2.5",
23 | "react-native-web": "^0.13.18",
24 | "react-navigation": "^4.4.3",
25 | "react-navigation-drawer": "^2.6.0",
26 | "react-navigation-stack": "^2.9.0"
27 | },
28 | "devDependencies": {
29 | "@babel/core": "~7.9.0"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 critique38
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/server/model/model.js:
--------------------------------------------------------------------------------
1 | const Pool = require('pg');
2 | require('dotenv').config();
3 |
4 | const PG_URI = process.env.DB_URI;
5 |
6 | const pool = new Pool({
7 | connectionString: PG_URI,
8 | });
9 |
10 | module.exports = {
11 | query: (text, params, callback) => {
12 | console.log('executed query --> ', text);
13 | return pool.query(text, params, callback);
14 | },
15 | };
16 |
17 | /*
18 | DB schemas below for reference
19 |
20 | CREATE TABLE questions (_id SERIAL PRIMARY KEY, question VARCHAR(8000) NOT NULL);
21 |
22 | CREATE TABLE questionnaire (_id SERIAL PRIMARY KEY, question1 INT NOT NULL, question2 INT, question3 INT, question4 INT, question5 INT, FOREIGN KEY (question1) REFERENCES questions(_id), FOREIGN KEY (question2) REFERENCES questions(_id), FOREIGN KEY (question3) REFERENCES questions(_id), FOREIGN KEY (question4) REFERENCES questions(_id), FOREIGN KEY (question5) REFERENCES questions(_id));
23 |
24 | CREATE TABLE users (_id SERIAL PRIMARY KEY, username VARCHAR(255) NOT NULL, name VARCHAR(255), authentication_token VARCHAR(255), email VARCHAR(255), other VARCHAR(255));
25 |
26 | CREATE TABLE links (_id SERIAL PRIMARY KEY, users INT NOT NULL, questionnaire INT NOT NULL, link VARCHAR(500) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), FOREIGN KEY (users) REFERENCES users(_id), FOREIGN KEY (questionnaire) REFERENCES questionnaire(_id));
27 |
28 | */
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const path = require('path');
4 | const port = 3838;
5 | const loginRouter = require('./router/loginRouter');
6 | const feedRouter = require('./router/feedRouter');
7 | const answersRouter = require('./router/answersRouter');
8 | const requestRouter = require('./router/requestRouter');
9 |
10 | app.use(express.json());
11 |
12 | app.use(express.urlencoded({extended: true}));
13 |
14 | // routes users to login
15 | app.use('/login', loginRouter)
16 |
17 | // route to allow users to give answers to requested feedback questionnaires
18 | app.use('/answers', answersRouter);
19 |
20 | // route allowing users to see their feedback feed
21 | app.use('/feed', feedRouter);
22 |
23 | // route to allow users to request feedback, AKA create a questionnaire
24 | app.use('/request', requestRouter);
25 |
26 |
27 |
28 | // app.use('*', express.static(path.resolve(__dirname, '../index.html')));
29 | app.use('/', (req, res) => {
30 | res.status(200).sendFile(path.resolve(__dirname, '../index.html'))
31 | });
32 |
33 | // currently error doesnt catch because '/' acounts for all possible paths
34 | // catch all error handler
35 | app.use('*', (req, res) => {
36 | res.status(404).send('You are wayyyyy lost my friend')
37 | })
38 |
39 | // global error handler
40 | app.use((err, req, res, next) => {
41 | const defaultError = {
42 | log: 'Express error',
43 | status: 500,
44 | message: { err: `An error occurred ${err}`}
45 | };
46 | const finalError = Object.assign(defaulterror, err);
47 | res.status(finalError.status).json(finalError.message);
48 | })
49 |
50 | app.listen(port, () => console.log(`Listening to all your thoughts on port ${port}`));
--------------------------------------------------------------------------------
/client/components/CreateFeedback.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import { StyleSheet, View, Text, Button } from 'react-native';
3 | import { FlatList, TextInput } from 'react-native-gesture-handler';
4 | import CreateList from '../components/CreateList'
5 | import CreateInput from '../components/CreateInput'
6 |
7 | export default function CreateFeedback({navigation}) {
8 |
9 | const [questions,setQuestions] = useState([
10 | {text: 'How can I be better?', id: '1'},
11 | {text: 'How can I do more?', id: '2'},
12 | {text: 'What is my biggest strength?', id: '3'},
13 | ])
14 |
15 | const submitHandler = (text) => {
16 | setQuestions((prevQuestions) => {
17 | return [
18 | {text: text, id: Math.random().toString()},
19 | ...prevQuestions
20 | ]
21 | })
22 | }
23 |
24 | const pressHandler = (id) => {
25 | setQuestions((prevQuestions) => {
26 | return prevQuestions.filter(quest => quest.id != id)
27 | })
28 | }
29 |
30 |
31 | const pressNext = () => {
32 | navigation.push('SendFeedback')
33 | }
34 |
35 | const pressBack = () => {
36 | navigation.pop();
37 | }
38 |
39 | return (
40 |
41 |
42 |
43 |
44 | (
47 |
50 | )}>
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 | );
62 | }
63 |
64 | const styles = StyleSheet.create({
65 | container: {
66 | padding: 24,
67 | },
68 | });
--------------------------------------------------------------------------------