Skip to content
Snippets Groups Projects
Commit 1bfc5ca4 authored by Andrine Kirstine Gudbrandsen's avatar Andrine Kirstine Gudbrandsen
Browse files

Merge branch 'remove-startview' into 'main'

Remove startview

See merge request !1
parents e1b22eaa d4dd956a
No related branches found
No related tags found
1 merge request!1Remove startview
Showing
with 326 additions and 596 deletions
import React, {useEffect, useState} from "react";
import {Route, Routes, useNavigate} from 'react-router-dom';
import {FetchResult, useLazyQuery, useMutation, useReactiveVar} from "@apollo/client";
import "./style/App.css"; import "./style/App.css";
import StartView from "./views/StartView"; import View from "./View";
import HomeView from "./views/HomeView";
import { LOAD_USER } from "./GraphQL/Queries";
import { SET_USER } from "./GraphQL/Mutations";
import { User } from "./interface/Interfaces";
import { requestGetUser, usersEmailVar } from './index';
import { wait } from "@testing-library/user-event/dist/utils";
const App = () => { const App = () => {
const [email, setEmail] = useState<string>(localStorage.getItem("email") || "");
const [errorMsg, setErrorMsg] = useState<string | null>(null);
const [makeUser, setMakeUser] = useState<boolean>(false);
const usersEmail = useReactiveVar<string>(usersEmailVar);
const requestUserData = useReactiveVar<boolean>(requestGetUser);
const navigateTo = useNavigate();
//The state of 'email' is set in StartView, once a user submits an email to log in.
const [getUser, {refetch, data: getUserData, loading: getUserLoading, error: getUserError }] = useLazyQuery(LOAD_USER, {
variables: {
input: {email: email}
}
});
//creates user with the state of 'email', which is set in StartView.
const [createUser] = useMutation(SET_USER,
{refetchQueries:
[{query: LOAD_USER, variables: {input: {email: email}}
}],
awaitRefetchQueries: true,
});
//triggers the above mutation once called. Checks for error in the response data object and in the mutation responce as well.
//if a new user has been created sucsessfully
const createNewUser = () =>{
createUser({variables: {
input: {email: email}
}
}).then((data) => {
if(data.errors) {
throw new Error(data.errors.toString());
} else if(!data.data) {
throw new Error("Could not create new user: Data is empty");
}
if(data.data.SetUser.email != ('' || null || undefined)){ //TODO her er problemet!!! Tar utgangspunkt i responsdataen fra mutasjonen og ikke
localStorage.setItem("email", data.data.SetUser.email);
usersEmailVar(data.data.SetUser.email);
navigateTo('/Home');
}
}).catch((error)=>{
setErrorMsg(error);
})
};
//the reactive variable that usersEmail points to, is set to '' once a user logs out (see the logout function in Header.tsx).
//usersEmail is set to something other than '' once a user has submitted an email on the correct format in the StartView.
useEffect(() => {
if ( usersEmail != ''){
setMakeUser(false);
getUser();
}
}, [requestUserData])
//email is set in localStorage once the user has
useEffect(() => {
if(getUserData != undefined){
if(getUserData.GetUser != null) {
//setEmail(usersEmail as string);
localStorage.setItem("email", getUserData.GetUser.email as string);
navigateTo('/Home');
setMakeUser(false)
}
else{
setMakeUser(true)
}
}else{
return;
}
}, [getUserData]) //
useEffect(() => {
if(makeUser==true){
createNewUser();
}
}, [makeUser])
//Users (the one with storedList) needs to be rendered before any CountryCards
return ( return (
<Routes> <View/>
<Route path="/" element={<StartView setEmail={(e: string) => { setEmail(e) }} />}/>
<Route path="/Home" element={<HomeView user={getUserData && getUserData.GetUser} poll={refetch}/>}/>
</Routes>
); );
}; };
export default App; export default App;
\ No newline at end of file
import {gql} from '@apollo/client'; import {gql} from '@apollo/client';
//Sets a user with an empty list //Updates user with savedList
export const SET_USER = gql` export const UPDATE_USER = gql`
mutation SetUser($input: EmailInput) { mutation UpdateUser($user: UserInput) {
SetUser(input: $input){ UpdateUser(user: $user){
email email
savedCountries { favList {
countryID
countryName
}
visList {
countryID countryID
isFav countryName
isVis
description
} }
} }
} }
`; `;
//Updates user with savedList
export const UPDATE_USER = gql` export const ADD_FAVOURITE = gql`
mutation UpdateUser($input: UserInput) { mutation AddFavourite($user: UserInput, $favourite: SavedCountryInput) {
UpdateUser(input: $input){ AddFavourites(user: $user, favourite: $favourite) {
email favList {
savedCountries { countryID
countryName
}
}
}
`;
export const ADD_VISITED = gql`
mutation AddVisited($user: UserInput, $visited: SavedCountryInput) {
AddVisited(user: $user, visited: $visited) {
visList {
countryID
countryName
}
}
}
`;
export const REMOVE_FAVOURITE = gql`
mutation RemoveFavourite($user: UserInput, $favourite: SavedCountryInput) {
RemoveFavourite(user: $user, favourite: $favourite) {
favList {
countryID
countryName
}
}
}
`;
export const REMOVE_VISITED = gql`
mutation RemoveVisited($user: UserInput, $visited: SavedCountryInput) {
RemoveVisited(user: $user, visited: $visited) {
visList {
countryID countryID
isFav countryName
isVis
description
} }
} }
} }
......
import { gql } from "@apollo/client"; import { gql } from "@apollo/client";
//loads a single user //loads a single user
export const LOAD_USER = gql` export const LOAD_USER = gql`
query GetUser($input: EmailInput) { query GetUser($email: String) {
GetUser(input: $input) { GetUser(email: $email) {
email email
savedCountries { favList {
countryID countryID
isFav countryName
isVis
description
}
}
} }
`; visList {
//loads a collection of countries
export const LOAD_COUNTRIES_BY_ID = gql`
query GetCountriesByID($input: [Int]) {
GetCountriesByID(input: $input) {
countryID countryID
countryName countryName
region }
population
area
gdp
} }
} }
`; `;
...@@ -43,43 +30,3 @@ export const LOAD_ALL_COUNTRIES = gql` ...@@ -43,43 +30,3 @@ export const LOAD_ALL_COUNTRIES = gql`
} }
} }
`; `;
\ No newline at end of file
//loads sorted countries
export const LOAD_COUNTRIES_SORT = gql`
query GetSortedCountries($input: SortBy, $offset: Int, $limit: Int) {
GetSortedCountries(input: $input, offset: $offset, limit: $limit) {
countryID
countryName
region
population
area
gdp
}
}
`;
//loads countries based on full name search
export const LOAD_COUNTRIES_SEARCH = gql`
query GetCountriesBySearch($input: [String], $offset: Int, $limit: Int) {
GetCountriesBySearch(input: $input, offset: $offset, limit: $limit) {
countryID
countryName
region
population
area
gdp
}
}
`;
//loads countries filtered by region
export const LOAD_COUNTRIES_FILTER = gql`
query GetCountriesByRegion($input: [String], $offset: Int, $limit: Int) {
GetCountriesByRegion(input: $input, offset: $offset, limit: $limit) {
countryID
countryName
region
population
area
gdp
}
}
`;
import React, { useState } from "react";
import "./style/View.css";
import { useQuery } from "@apollo/client";
import {LOAD_ALL_COUNTRIES} from "./GraphQL/Queries";
import { Country } from "./interface/Interfaces";
import CountryCard, { CountryCardEvent } from "./components/CountryCard";
import SavedList from "./components/SavedList";
import Header from "./components/Header";
import Filter from "./components/Filter";
import Search from "./components/Search"
import Fab from "@mui/material/Fab";
import { Typography } from "@mui/material";
const View = () => {
//const [errorMessage, setErrorMessage] = useState<string>("ERROR!");
const [isMobile, setIsMobile] = useState(false);
//const [search, setSearch] = useState<string>('');
const regionDefault: string[] = [];
const { error, loading, fetchMore, refetch, data } = useQuery(LOAD_ALL_COUNTRIES, {
variables: { offset: 0, limit: 10, search: "", sort: {}, region: regionDefault},
});
return (
<>
<div id="View">
<SavedList/>
<Header/>
<div id='searchBox'>
<Typography id='searchInfo' className='searchEl' variant="h6" component="div" sx={{ flexGrow: 1 }}>Search for a country you have visited or want to visit...</Typography>
<div id="searchElements">
<Search onChange={s => refetch({search: s})} />
{<h4> OR </h4>}
<Filter id='Filter' setFilter={(r: string[]) => refetch({region: r})} />
</div>
</div>
<div id='searchResults'>
{loading || error ? (
<>
{error && <p> Could not load countries: {error.message} </p>}
{loading && <p> Loading... Please wait.</p>}
</>
) : (
<>
<h2>All countries</h2>
<div className="Countries">
{data &&
data.GetAllCountries.map((country: Country) => {
return (
<CountryCard
key={country.countryID}
country={country}
isFav={false}
isVis={false}
countryAction={function (countryID: number, event: CountryCardEvent): void {
throw new Error("Function not implemented.");
} } />
);
})}
{data && (
<Fab variant="extended" id = 'loadMore' size="medium" color="primary" aria-label="Press to load more countries" onClick={async (inView) => {
const currentLen = data.GetAllCountries.length || 0;
await fetchMore({
variables: {
offset: currentLen,
limit: currentLen+10,
},
});
}} sx={{borderRadius:10, minHeight: '40px', maxHeight: '40px', minWidth: '50%'}}>
Load More Countries
</Fab>
)}
</div>
</>
)}
</div>
</div>
</>
);
};
export default View;
\ No newline at end of file
import { import {LOAD_ALL_COUNTRIES} from "../GraphQL/Queries";
LOAD_COUNTRIES_BY_ID,
LOAD_ALL_COUNTRIES
} from "../GraphQL/Queries";
import { MockedProvider } from "@apollo/client/testing"; import { MockedProvider } from "@apollo/client/testing";
export const mockedFilteredCCountryQuery = { export const mockedFilteredCCountryQuery = {
request: { request: {
query: LOAD_COUNTRIES_BY_ID, query: LOAD_ALL_COUNTRIES,
variables: { variables: {
countryID: 1, countryID: 1,
countryName: "Afganistan", countryName: "Afganistan",
......
import "../style/Card.css"
import React, {useState} from 'react' import React, {useState} from 'react'
interface CardProps { interface CardProps {
......
...@@ -13,7 +13,7 @@ import DoneOutlineIcon from '@mui/icons-material/DoneOutline'; ...@@ -13,7 +13,7 @@ import DoneOutlineIcon from '@mui/icons-material/DoneOutline';
export interface countryCardT { export interface countryCardT {
country: Country; country: Country;
isFav: boolean; isFav: boolean;
isVisited: boolean; isVis: boolean;
countryAction: (countryID: number, event: CountryCardEvent) => void; countryAction: (countryID: number, event: CountryCardEvent) => void;
}; };
...@@ -23,9 +23,7 @@ export enum CountryCardEvent { ...@@ -23,9 +23,7 @@ export enum CountryCardEvent {
Visited Visited
}; };
const CountryCard: React.FC<countryCardT> = ({ country, isFav, isVis, countryAction }) => {
const CountryCard: React.FC<countryCardT> = ({ country, isFav, isVisited, countryAction }) => {
const [expand, setExpand] = useState<boolean>(false); const [expand, setExpand] = useState<boolean>(false);
...@@ -42,6 +40,7 @@ const CountryCard: React.FC<countryCardT> = ({ country, isFav, isVisited, countr ...@@ -42,6 +40,7 @@ const CountryCard: React.FC<countryCardT> = ({ country, isFav, isVisited, countr
//CountryCard show different info based on whether countries are favourited/visited or not. //CountryCard show different info based on whether countries are favourited/visited or not.
//Toggles between expanded and default view on button click. //Toggles between expanded and default view on button click.
return ( return (
......
import React, { useState } from 'react';
import { Country, SavedCountry, User } from "../interface/Interfaces";
import Fab from "@mui/material/Fab";
import FavoriteIcon from '@mui/icons-material/Favorite';
import CheckIcon from '@mui/icons-material/Check';
import Card from './Card';
export interface FavouriteCountryInterface {
country: Country;
onChange: (country: Country, type: string) => void;
}
const FavouriteCountry: React.FC<FavouriteCountryInterface> = ( { country, onChange} ) => {
const [editing, setEditing] = useState<boolean>(false);
//const [textarea, setTextarea] = useState<string>('');
return (
<Card className="card favCountry" id={country.countryID.toString()}>
<p aria-label='country name'>{ country.countryName }</p>
<>
<Fab title='Remove favorite from travel diary' id="removeCountry" size="small" color="primary" onClick={() => onChange(country, "unfav")} aria-description="Click this button to mark country as visited" >
<FavoriteIcon />
</Fab>
</>
<>
<Fab title='Remove visited from travel diary' id="removeCountry" size="small" color="primary" onClick={() => onChange(country, "unvisit")} aria-description="Click this button to mark country as visited" >
<CheckIcon />
</Fab>
</>
</Card>
)
}
export default FavouriteCountry;
\ No newline at end of file
import * as React from "react"; import * as React from "react";
import { darkThemeVar } from "../index";
import { useReactiveVar } from "@apollo/client";
import { Theme, ThemeProvider, useTheme } from "@mui/material/styles";
import OutlinedInput from "@mui/material/OutlinedInput"; import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel"; import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
...@@ -12,11 +8,8 @@ import Stack from '@mui/material/Stack'; ...@@ -12,11 +8,8 @@ import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import Fab from "@mui/material/Fab"; import Fab from "@mui/material/Fab";
const ITEM_HEIGHT = 48; const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8; //TODO Inplementer hooks i homeview const ITEM_PADDING_TOP = 8;
const MenuProps = { const MenuProps = {
PaperProps: { PaperProps: {
style: { style: {
...@@ -35,18 +28,7 @@ const area = [ ...@@ -35,18 +28,7 @@ const area = [
"Oceania", "Oceania",
]; ];
function getStyles(type: any, typeName: any, theme: any) {
return {
fontWeight:
typeName.indexOf(type) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
export default function Filter({ setFilter }: any) { export default function Filter({ setFilter }: any) {
const darkTheme = useReactiveVar<Theme>(darkThemeVar);
const theme = useTheme();
const [typeName, setTypeName] = React.useState([]); const [typeName, setTypeName] = React.useState([]);
const handleChange = (event: any) => { const handleChange = (event: any) => {
...@@ -62,8 +44,6 @@ export default function Filter({ setFilter }: any) { ...@@ -62,8 +44,6 @@ export default function Filter({ setFilter }: any) {
return ( return (
<div id='Filter'> <div id='Filter'>
<ThemeProvider theme={darkTheme}>
<FormControl sx={{ width: '100%'}} color="success"> <FormControl sx={{ width: '100%'}} color="success">
<InputLabel <InputLabel
id="filterLabel" id="filterLabel"
...@@ -87,18 +67,12 @@ export default function Filter({ setFilter }: any) { ...@@ -87,18 +67,12 @@ export default function Filter({ setFilter }: any) {
<MenuItem <MenuItem
key={name} key={name}
value={name} value={name}
style={getStyles(name, typeName, theme)}
> >
{name} {name}
</MenuItem> </MenuItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
</ThemeProvider>
</div> </div>
); );
} }
\ No newline at end of file
import React from 'react'; import * as React from 'react';
import { useNavigate } from "react-router-dom"; import { styled, ThemeProvider, createTheme } from '@mui/material/styles';
import { useReactiveVar } from '@apollo/client';
import { darkThemeVar, usersEmailVar } from '../index';
import GlobeLogo from "../resources/globe.png"
import { createTheme, styled, useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import CssBaseline from '@mui/material/CssBaseline';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'; import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { ThemeProvider, Theme } from '@mui/material/styles'; import TravelExploreIcon from '@mui/icons-material/TravelExplore';
import Fab from '@mui/material/Fab';
import ImageListItem from '@mui/material/ImageListItem';
const drawerWidth = 240; const drawerWidth = 240;
interface AppBarProps extends MuiAppBarProps { interface AppBarProps extends MuiAppBarProps {
...@@ -25,84 +14,39 @@ interface AppBarProps extends MuiAppBarProps { ...@@ -25,84 +14,39 @@ interface AppBarProps extends MuiAppBarProps {
const AppBar = styled(MuiAppBar, { const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open', shouldForwardProp: (prop) => prop !== 'open',
}) })<AppBarProps>(({ theme, open }) => ({
transition: theme.transitions.create(['margin', 'width'], {
<AppBarProps>(({ theme, open }) => ({transition: theme.transitions.create(['margin', 'width'], {
}), }),
...(open && { ...(open && {
/*width: `calc(100% - ${drawerWidth}px)`,*/ width: `calc(100% - ${drawerWidth}px)`,
width: `100%`,
marginLeft: `${drawerWidth}px`, marginLeft: `${drawerWidth}px`,
transition: theme.transitions.create(['margin', 'width'], { transition: theme.transitions.create(['margin', 'width'], {
}), }),
}), }),
})); }));
export default function PersistentDrawerLeft() { export default function PersistentDrawerLeft() {
const darkTheme = useReactiveVar<Theme>(darkThemeVar); const colorTheme = createTheme({
const usersEmail = useReactiveVar<string>(usersEmailVar);
const navigateTo = useNavigate();
const logOut = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
usersEmailVar('');
navigateTo("/");
}
const greyTheme = createTheme({
palette: { palette: {
primary: { primary: {
main: '#3b3b3b', main: '#324736e2',
}, },
}, },
}); });
//<CssBaseline />
return ( return (
<Box sx={{ display: 'flex' }}>
<Box sx={{ flexGrow: 1 }}> <CssBaseline />
<ThemeProvider theme={colorTheme}>
<AppBar color="primary">
<ThemeProvider theme={greyTheme}>
<AppBar color='primary'>
<Toolbar> <Toolbar>
<ImageListItem key={GlobeLogo} > <Typography variant="h6" noWrap component="div">
<img src={GlobeLogo} alt="Travel diary logo" loading="lazy" id='headerLogo' /> <TravelExploreIcon sx={{ fontSize: 45 }} /> Travel Diary
</ImageListItem>
<Typography variant="h6" component="div"> Travel Diary </Typography>
<Typography variant="h6" component="div" id='space' sx={{ flexGrow: 1 }}></Typography>
<Typography variant="h6" component="div" id='usersEmailHeader' aria-label='e-mail' aria-description='email of the user that is logged in' sx={{ paddingRight:'2%'}}>
{usersEmail}
</Typography> </Typography>
<ThemeProvider theme={darkTheme}>
<Fab variant="extended" id="logOutBtn" size="medium" color="primary" aria-label="press button to log out" onClick={(e) => logOut(e)}>
Log out
</Fab>
</ThemeProvider>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
</ThemeProvider> </ThemeProvider>
</Box> </Box>
); );
} }
\ No newline at end of file
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { LOAD_USER } from "../GraphQL/Queries";
import { LOAD_COUNTRIES_BY_ID } from "../GraphQL/Queries"; import { Country, SavedCountry, User } from '../interface/Interfaces';
import { useQuery } from '@apollo/client'; import { useLazyQuery, useMutation } from "@apollo/client";
import { Country, SavedCountry } from '../interface/Interfaces'; import FormControl from '@mui/material/FormControl';
import FavouriteCountry from './FavouriteCountry'; import InputLabel from '@mui/material/InputLabel';
import OutlinedInput from '@mui/material/OutlinedInput';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import "../style/SavedList.css";
import { ADD_FAVOURITE, ADD_VISITED, REMOVE_FAVOURITE, REMOVE_VISITED } from '../GraphQL/Mutations';
export interface SavedListProps { export interface SavedListProps {
countries: SavedCountry[]; countries: SavedCountry[];
onChange: (country: Country, change: any) => void; onChange: (country: Country, change: any) => void;
} }
//this function displays the SavedCountry elements in the users storedList //this function displays the SavedCountry elements in the users storedList
const SavedList: React.FC<SavedListProps> = ( { countries, onChange } ) => { const SavedList = () => {
const [expand, setExpand] = useState<boolean>(false); const [expand, setExpand] = useState<boolean>(false);
const [editing, setEditing] = useState<boolean>(false); const [editing, setEditing] = useState<boolean>(false);
const [user, setUser] = useState<String>();
const [currentUser, setCurrentUser] = useState<User>();
const [getUser, {data: getUserData, loading: getUserLoading, error: getUserError }] = useLazyQuery(LOAD_USER, {
variables: {email: user}
});
const [removeVis, {data: removeVisData}] = useMutation(REMOVE_VISITED);
const [removeFav, {data: removeFavData}] = useMutation(REMOVE_FAVOURITE);
const [addVis, { data: addVisData}] = useMutation(ADD_VISITED);
const {error, loading, data, refetch} = useQuery(LOAD_COUNTRIES_BY_ID, { const [addFav, { data: addFavData}] = useMutation(ADD_FAVOURITE);
variables: {
input: countries.map(c => c.countryID) const updateEmail = (email: String) => {
setUser(email);
} }
});
const handleSubmit = () => {
console.log("Fetching user"+user);
getUser();
setCurrentUser(getUserData);
}
const handleRemoveFav = (id: Number, name: String) => {
console.log("Handle remove Fav "+id);
useEffect(() => { if (currentUser) {
refetch({input: countries.map(c => c.countryID)}) removeFav({variables: {
}, [countries, refetch]) email: currentUser?.email,
favourite: {
countryID: id,
countryName: name
}
}});
currentUser.favList = removeFavData;
}
}
const handleRemoveVis = (id: Number, name: String) => {
console.log("Handle remove vis "+id);
if (currentUser) {
removeVis({variables: {
email: currentUser?.email,
favourite: {
countryID: id,
countryName: name
}
}});
currentUser.visList = removeVisData;
}
}
useEffect(() => {
}, [currentUser])
return ( return (
<div id='savedList' > <div id='savedList' >
<FormControl id='loginForm' onSubmit={(e) => {e.preventDefault(); handleSubmit()}}>
<InputLabel htmlFor="inputEmail">E-mail</InputLabel>
<OutlinedInput id="inputEmail" onChange={(e) => updateEmail(e.target.value)} label="E-mail*" aria-label="email input field"/>
<button type="button" onClick={(e) => {
e.preventDefault();
handleSubmit();
}}>Submit</button>
</FormControl>
<div className='top' onClick={() =>{setExpand(!expand)}}> <div className='top' onClick={() =>{setExpand(!expand)}}>
<h3>My travel diary</h3> <h2>My travel diary</h2>
<p >{expand? <KeyboardArrowUpIcon/> : <KeyboardArrowDownIcon/>}</p> <p >{expand? <KeyboardArrowUpIcon/> : <KeyboardArrowDownIcon/>}</p>
</div> </div>
<div id="savedListContent"> <div id="favListContent"> <h3>Favorite Countries</h3>
{expand?
<>
<>
{getUserError && <p> Error when loading data: {getUserError.message} </p>}
{getUserLoading && <p> Loading... Please wait. </p> }
</>
<>
{currentUser &&
currentUser.favList.map((c: { countryID: number; countryName: string; }) => <li key={c.countryID}>{c.countryName}<button onClick={() => handleRemoveFav(c.countryID, c.countryName)}>Remove</button></li>)
}
</>
</>
:
null
}
</div>
<div id="visListContent"> <h3>Visited Countries</h3>
{expand? {expand?
<> <>
<> <>
{error && <p> Error when loading data: {error.message} </p>} {getUserError && <p> Error when loading data: {getUserError.message} </p>}
{loading && <p> Loading... Please wait. </p> } {getUserLoading && <p> Loading... Please wait. </p> }
</> </>
<> <>
{data && data.GetCountriesByID && {currentUser &&
data.GetCountriesByID.map((country: Country) => { currentUser.visList.map((c: { countryID: number; countryName: string; }) => <li key={c.countryID}>{c.countryName}<button onClick={() => handleRemoveVis(c.countryID, c.countryName)}>Remove</button></li>)
return <FavouriteCountry key={country.countryID} country={country} onChange={onChange} />
})
} }
</> </>
</> </>
...@@ -67,6 +130,4 @@ const SavedList: React.FC<SavedListProps> = ( { countries, onChange } ) => { ...@@ -67,6 +130,4 @@ const SavedList: React.FC<SavedListProps> = ( { countries, onChange } ) => {
</div> </div>
) )
}; };
export default SavedList; export default SavedList;
\ No newline at end of file
import React from 'react'; import React from 'react';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import { useReactiveVar } from "@apollo/client";
import { darkThemeVar } from "../index";
import { Theme, ThemeProvider } from '@mui/material/styles';
export interface SearchProps { export interface SearchProps {
onChange: (search: string) => void onChange: (search: string) => void
} }
export default function Search( { onChange } : SearchProps) { export default function Search( { onChange } : SearchProps) {
const darkTheme = useReactiveVar<Theme>(darkThemeVar);
return ( return (
<> <>
<ThemeProvider theme={darkTheme}>
<TextField <TextField
color='secondary' color='secondary'
id="filled-basic" id="filled-basic"
...@@ -25,7 +16,6 @@ export default function Search( { onChange } : SearchProps) { ...@@ -25,7 +16,6 @@ export default function Search( { onChange } : SearchProps) {
onChange={e => onChange(e.target.value)} onChange={e => onChange(e.target.value)}
helperText="First letter upper-case, the rest lower-case (Example; Norway)" helperText="First letter upper-case, the rest lower-case (Example; Norway)"
/> />
</ThemeProvider>
</> </>
); );
} }
\ No newline at end of file
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import { ApolloClient, InMemoryCache, ApolloProvider, makeVar} from '@apollo/client'; import { ApolloClient, InMemoryCache, ApolloProvider} from '@apollo/client';
import {Route, Routes, useNavigate} from 'react-router-dom';
import {HashRouter} from 'react-router-dom';
import { Theme, createTheme } from '@mui/material/styles';
import { SavedCountry, User } from './interface/Interfaces';
import './style/index.css';
import App from './App'; import App from './App';
import { offsetLimitPagination } from '@apollo/client/utilities'; import { offsetLimitPagination } from '@apollo/client/utilities';
//import reportWebVitals from './reportWebVitals';
export const cache = new InMemoryCache({ export const cache = new InMemoryCache({
typePolicies: { typePolicies: {
...@@ -28,29 +19,6 @@ const client = new ApolloClient({ ...@@ -28,29 +19,6 @@ const client = new ApolloClient({
uri: 'http://it2810-63.idi.ntnu.no:8080/graphql' uri: 'http://it2810-63.idi.ntnu.no:8080/graphql'
}); });
//dark theme for MaterialUI components;
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
export const darkThemeVar = makeVar<Theme>(darkTheme);
export const usersEmailVar = makeVar<string>('');
export const requestGetUser = makeVar<boolean>(false);
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement document.getElementById('root') as HTMLElement
); );
...@@ -58,10 +26,7 @@ root.render( ...@@ -58,10 +26,7 @@ root.render(
<ApolloProvider client={client}> <ApolloProvider client={client}>
<React.StrictMode> <React.StrictMode>
<HashRouter>
<App /> <App />
</HashRouter>
</React.StrictMode> </React.StrictMode>
</ApolloProvider> </ApolloProvider>
); );
\ No newline at end of file
export interface Country { export interface Country {
countryID: number, countryID: number,
countryName: string, countryName: string,
...@@ -9,16 +7,13 @@ export interface Country { ...@@ -9,16 +7,13 @@ export interface Country {
gdp: number gdp: number
} }
export interface SavedCountry { export interface SavedCountry {
countryID: number, countryID: number,
isFav: boolean, countryName: string
isVis: boolean,
description: string
} }
export interface User { export interface User {
email: string, email: string,
savedCountries: SavedCountry[] favList: SavedCountry[],
visList: SavedCountry[]
} }
\ No newline at end of file
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
font-family: "Roboto","Helvetica","Arial",sans-serif; font-family: "Roboto","Helvetica","Arial",sans-serif;
} }
#logOutBtn{ #logOutBtn{
right:0px; right:0px;
} }
...@@ -13,8 +12,6 @@ ...@@ -13,8 +12,6 @@
max-width: 70px; max-width: 70px;
} }
.errorMsgField{ .errorMsgField{
color: red; color: red;
display: flex; display: flex;
...@@ -22,6 +19,6 @@ ...@@ -22,6 +19,6 @@
justify-content: center; justify-content: center;
} }
.body {
background-color: black;
}
\ No newline at end of file
/* Default style for all Cards */
.card{
color: white;
border-radius: 8px;
padding: 2%;
max-width: 100%;
border: 4;
contain: content;
overflow: none;
background-color: #3b3b3b;
}
.card:hover{
transform: scale(1.01);
}
/* mobile */
@media only screen and (max-width: 414px) {
.card{
font-size: 10pt;
}
.card h4{
font-size: 12pt;
}
}
\ No newline at end of file
...@@ -5,14 +5,12 @@ ...@@ -5,14 +5,12 @@
max-width: 90%; max-width: 90%;
contain: content; contain: content;
overflow: none; overflow: none;
background-color: #3b3b3b; background-color: #213630;
width: 70vw; width: 70vw;
margin-bottom: 10px; margin-bottom: 10px;
position: relative; position: relative;
} }
#top { #top {
display: grid; display: grid;
grid-template-columns: 8fr 1fr 1fr; grid-template-columns: 8fr 1fr 1fr;
...@@ -25,13 +23,11 @@ ...@@ -25,13 +23,11 @@
margin-bottom: 5%; margin-bottom: 5%;
} }
#name{ #name{
display: grid; display: grid;
justify-content: left; justify-content: left;
} }
p{ p{
display: grid; display: grid;
grid-template-columns: auto auto; grid-template-columns: auto auto;
...@@ -46,18 +42,6 @@ p{ ...@@ -46,18 +42,6 @@ p{
margin: 1% 1%; margin: 1% 1%;
} }
#description {
border: 1px solid transparent;
border-radius: 10px;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.13);
padding: 1%;
}
/* smaller screens */ /* smaller screens */
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
.cardCountry{ .cardCountry{
......
.favList{
width: 100%;
display: grid;
grid-template-rows: auto auto auto auto;
}
\ No newline at end of file
#savedList{
display: grid;
color: rgb(252, 252, 252);
margin-top: 50px;
width:40%;
padding: 3%;
height: fit-content;
background: #5a4523d7;
contain: content;
overflow: scroll;
border: 2px #f2f1f4 solid;
border-radius: 10px;
grid-template-rows: auto;
}
#favListContent, #visListContent{
display: grid;
flex-direction: column;
}
#inputEmail.label{
color: white;
}
.button{
width: min-content;
display: grid;
color: #5a4523d7;
background-color: #f1f1f1;
}
.favoriteCountries{
display: inline-block;
border: 1px solid rgb(194, 203, 194);
}
.visitedCountries{
display: inline-block;
border: 1px solid rgb(194, 203, 194);
}
\ No newline at end of file
/*
Styling the Card containing the input field for the userID
*/
.App{
padding-top: 10%;
}
#StartView{
margin-top: 10vh;
}
#logo{
display: flex;
justify-content: center;
margin-bottom: 10vh;
}
.loginCard {
width: 50%;
margin: auto;
padding: 6%;
min-width: 200px;
display: grid;
grid-template-rows: repeat(auto-fit, minmax(20%, 1fr));
row-gap: 1em;
grid-template-columns: 1fr;
}
#loginForm{
display: grid;
grid-template-rows: repeat(auto-fit, minmax(50px, 1fr));
row-gap: 10%;
padding-bottom: 10%;
}
#introText{
font-size: 1.5em;
margin: 2%;
display: flex;
justify-content: center;
}
#submitEmailContainer, #globeLogo{
display: flex;
flex-direction: row;
justify-content: center;
}
/* Smart phone */
@media only screen and (max-width: 414px) {
.loginCard {
width: 80%;
margin: auto;
display: grid;
grid-template-rows: repeat(auto-fit, minmax(20%, 1fr));
row-gap: 1em;
grid-template-columns: 1fr;
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment