Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
"browser": true,
"es2021": true
},
"extends": ["plugin:react/recommended", "prettier"],
"extends": [
"plugin:react/recommended",
"prettier",
"plugin:prettier/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
Expand Down
11,631 changes: 5,792 additions & 5,839 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,38 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@fortawesome/fontawesome-free": "^6.7.1",
"@fortawesome/fontawesome-svg-core": "^6.7.1",
"@fortawesome/free-brands-svg-icons": "^6.7.1",
"@fortawesome/free-regular-svg-icons": "^6.7.1",
"@fortawesome/free-solid-svg-icons": "^6.7.1",
"@fortawesome/react-fontawesome": "^0.2.2",
"axios": "^1.7.7",
"axios": "^1.7.9",
"mapbox-gl": "^3.8.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/plugin-transform-private-property-in-object": "^7.25.9",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.15.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"eslint": "^8.57.1",
"@eslint/js": "^9.16.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.5.2",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"eslint": "^9.16.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.2",
"globals": "^15.12.0",
"husky": "^9.1.6",
"globals": "^15.13.0",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"prettier": "3.3.3",
"prettier": "^3.4.2",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5",
"typescript-eslint": "^8.14.0",
"web-vitals": "^2.1.4",
"tailwindcss": "^3.4.15"
"tailwindcss": "^3.4.16",
"typescript": "^4",
"typescript-eslint": "^8.17.0"
},
"scripts": {
"start": "react-scripts start",
Expand Down
22 changes: 22 additions & 0 deletions src/Components/CatCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import CatFromAxios from '../Interfaces/CatFromAxios';
import Card from './Styling/Card';

interface Props {
cat: CatFromAxios;
}

export default function CatCard({ cat }: Props) {
return (
<Card heading={cat.name}>
<div className="flex justify-between">
<img src={cat.picture_url ?? ''} alt={cat.name} className="w-20" />
<div>
<p>Level: {cat.battle_profile.level.toString()}</p>
<p>XP: {cat.battle_profile.xp.toString()}</p>
</div>
<p>{cat.description ?? 'A good kitty'}</p>
</div>
</Card>
);
}
128 changes: 117 additions & 11 deletions src/Components/CatProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,144 @@
import React from 'react';
import { useState, useEffect, ChangeEvent } from 'react';
import {
getCatsProfiles,
deleteCatProfile,
updateCatProfile,
} from '../network';
import FormInput from './Styling/FormInput';
import Button from './Styling/Button';
import H3 from './Styling/H3';
import CatFromAxios from '../Interfaces/CatFromAxios';
import Messages from './Styling/Messages';

const { REACT_APP_LOGGED_IN_USER } = process.env;

function CatProfile() {
const [catName, setCatName] = useState<string>('');
const [catPicture, setCatPicture] = useState<string | null>('');
const [catDescription, setCatDescription] = useState<string | null>('');
const [catProfiles, setCatProfiles] = useState<CatFromAxios[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [message, setMessage] = useState<string>('');

useEffect(() => {
getCatsProfiles(REACT_APP_LOGGED_IN_USER as string).then(
(fetchedProfiles) => {
if (Array.isArray(fetchedProfiles) && fetchedProfiles.length > 0) {
const profile = fetchedProfiles[0];
setCatProfiles(fetchedProfiles);
setCatName(profile.name);
setCatPicture(profile.picture_url);
setCatDescription(profile.description);
}
setIsLoading(false);
}
);
}, []);

if (isLoading) {
return <p>Loading...</p>;
}

const handleProfileEditBy = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;

if (name === 'name') {
setCatName(value);
} else if (name === 'pictureurl') {
setCatPicture(value);
} else if (name === 'description') {
setCatDescription(value);
}
};

const handleSavedChanges = () => {
const updatedProfile: CatFromAxios = {
id: catProfiles[0]?.id,
name: catName,
picture_url: catPicture,
description: catDescription,
device_id: catProfiles[0].device_id,
owner_id: catProfiles[0].owner_id,
updated_at: new Date().toISOString(),
created_at: new Date().toISOString(),
deleted_at: null,
battle_profile: catProfiles[0].battle_profile,
};
updateCatProfile(updatedProfile)
.then(() => {
setCatProfiles((previousProfiles) =>
previousProfiles?.map((profile) =>
profile.id === updatedProfile.id ? updatedProfile : profile
)
);
setMessage('Updates have been saved');
})
.catch(() => {
setMessage('Updates havent been saved');
});
};

const handleDeleteProfile = () => {
deleteCatProfile(REACT_APP_LOGGED_IN_USER as string)
.then(() => {
setCatProfiles((fetchedProfiles) =>
fetchedProfiles.filter((profile) => profile.id !== profile.id)
);
setMessage('Profile Removed');
})
.catch(() => {
setMessage('Failed to delete the profile');
});
};

return (
<div className="">
<div className="w-72 p-20 m-auto bg-emerald-100 ">
<H3>Cat&apos;s Profile</H3>
{message && (
<>
{message === 'Updates have been saved' && (
<Messages text="Updates have been saved" status="success" />
)}
{message === "Updates haven't been saved" && (
<Messages text="Updates haven't been saved" status="error" />
)}
{message === 'Profile Removed' && (
<Messages text="Profile Removed" status="success" />
)}
{message === 'Failed to delete the profile' && (
<Messages text="Failed to delete the profile" status="error" />
)}
</>
)}
<div className="flex flex-col">
<FormInput
label="Name"
type="text"
name="name"
value="Cat name"
onChange={() => {}}
value={catName}
onChange={handleProfileEditBy}
/>
<FormInput
label="Pricture"
label="Picture"
type="text"
name="pictureurl"
value="Picture URL"
onChange={() => {}}
value={catPicture ?? ''}
onChange={handleProfileEditBy}
/>
<FormInput
label="Description"
type=""
type="text"
name="description"
value="A good girl"
onChange={() => {}}
value={catDescription ?? ''}
onChange={handleProfileEditBy}
/>
<Button onClick={() => {}}>Save</Button>
<Button type="submit" onClick={handleSavedChanges}>
Submit
</Button>
<Button onClick={handleDeleteProfile}>Delete</Button>
</div>
</div>
);
}

export default CatProfile;
111 changes: 77 additions & 34 deletions src/Components/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,92 @@
import React, { useContext, useState } from 'react';
import { UserContext } from '../Contexts/UserContext';
// import { registerUser } from '../network';
import FormInput from './Styling/FormInput';
import H2 from './Styling/H2';
import Button from './Styling/Button';
import ModalPopover from './Styling/ModalPopover';

export default function Login() {
const { setUsername, setUserId, setHome } = useContext(UserContext);
const [formUsername, setFormUsername] = useState<string>('');
const [latitude, setLatitude] = useState<string>('');
const [longitude, setLongitude] = useState<string>('');
const [errorMessage, setErrorMessage] = useState<string>('');

function isValidLat(input: string): boolean {
const value = parseFloat(input);
return !isNaN(value) && value >= -90 && value <= 90;
}

function isValidLong(input: string): boolean {
const value = parseFloat(input);
return !isNaN(value) && value >= -180 && value <= 180;
}

function handleSubmit(e: React.FormEvent) {
e.preventDefault();

// For demo

setUsername('user1');
setUserId('cm3op7iwu0000jrcqa60tc9kv');
// return registerUser(formUsername).then(
// (newUser: null | { username: string }) => {
// if (!newUser) {
// setErrorMessage(
// 'Sorry, there was an error creating an account. Please try again later.'
// );
// } else {
// setUsername(newUser.username);
// setHome([parseFloat(latitude), parseFloat(longitude)]);
// }
// }
// );
}

return (
<form onSubmit={handleSubmit}>
<label>
User
<input
type="text"
name="username"
placeholder="Username"
value={formUsername}
onChange={({ target: { value } }) => setFormUsername(value)}
/>
</label>
<p>Home Location</p>
<label>
Lat.
<input
type="text"
name="latitude"
placeholder="Latitude"
value={latitude}
onChange={({ target: { value } }) => setLatitude(value)}
/>
</label>
<label>
Long.
<input
type="text"
name="longitude"
placeholder="Longitude"
value={longitude}
onChange={({ target: { value } }) => setLongitude(value)}
/>
</label>
<button type="submit">Create User</button>
</form>
<>
<ModalPopover>
<H2>Login</H2>
<form onSubmit={handleSubmit}>
<FormInput
label="User"
type="text"
name="username"
placeholder="Username"
value={formUsername}
onChange={({ target: { value } }) => setFormUsername(value)}
/>
<section>
<H2>Home Location</H2>
<FormInput
label="Lat."
type="text"
name="latitude"
placeholder="Latitude"
value={latitude}
onChange={({ target: { value } }) => setLatitude(value)}
/>
<FormInput
label="Long."
type="text"
name="longitude"
placeholder="Longitude"
value={longitude}
onChange={({ target: { value } }) => setLongitude(value)}
/>
</section>
{errorMessage && <p>{errorMessage}</p>}
<Button
type="submit"
disabled={
!formUsername || !isValidLat(latitude) || !isValidLong(longitude)
}
>
Create User
</Button>
</form>
</ModalPopover>
</>
);
}
Loading