Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7eeb938
initial files and page outline
Bianka2112 May 2, 2025
b81a88d
intial header
Bianka2112 May 2, 2025
5688e0f
draft template of components for form and messageboard
Bianka2112 May 2, 2025
2c1a2c1
basic css for form
Bianka2112 May 20, 2025
2244222
form button css
Bianka2112 May 20, 2025
cb55d63
msgBoard css, heartbutton, timestamp
Bianka2112 May 20, 2025
220f4c8
code loader, code API fetch, needs card
Bianka2112 May 20, 2025
db4daf9
format api into cards
Bianka2112 May 20, 2025
90308e3
update timestamp, heart count
Bianka2112 May 20, 2025
31ddc43
title banner animation
Bianka2112 May 20, 2025
5d8ea3d
msg validation, fix overflow msg from API
Bianka2112 May 21, 2025
d216fbc
back to top btn
Bianka2112 May 21, 2025
efa3ffd
fixed post request, refactored all pages to lift state correctly
Bianka2112 May 22, 2025
2c5805a
post url fix and fx update
Bianka2112 May 22, 2025
3a30f26
reformat styled comps to own page
Bianka2112 May 22, 2025
8352e91
update loader style
Bianka2112 May 22, 2025
d2be90c
add like fx! 🥳
Bianka2112 May 22, 2025
7afb8f2
reformat likebutton, moved styling
Bianka2112 May 22, 2025
f22a158
like animation
Bianka2112 May 22, 2025
1fad486
subtle background, styling
Bianka2112 May 23, 2025
b2eb1f2
update styling to match, format textarea
Bianka2112 May 23, 2025
17da1c6
fix form button to fit
Bianka2112 May 23, 2025
04a73a9
deployed etlify link
Bianka2112 May 23, 2025
7ac39eb
fix header position
Bianka2112 May 23, 2025
f06b455
update api link, fixed btn hover disabled
Bianka2112 May 27, 2025
795d062
update heart like api
Bianka2112 May 27, 2025
2d1c267
test backend API works and query param works, good.
Bianka2112 Jun 2, 2025
b9e6d11
create dotenv, update URLs in code, cleanup code
Bianka2112 Jun 10, 2025
b34e14e
delete thought fx
Bianka2112 Jun 10, 2025
41609e6
refactor to zustand, update cleaner code, features work, so far
Bianka2112 Jun 10, 2025
92cec54
add edit fx
Bianka2112 Jun 11, 2025
7824cec
font touchup
Bianka2112 Jun 11, 2025
2bec342
favicon added, index update
Bianka2112 Jun 11, 2025
77d0537
incomplete, but add loginModal to start auth connection to backend
Bianka2112 Jun 11, 2025
4d009a2
still incomp, created useAuthStore outline
Bianka2112 Jun 11, 2025
0992a95
rm bkground hearts, index.css, building up auth features(incomplete)
Bianka2112 Jun 17, 2025
0dc3a3e
signupform, loginform, post and like fx
Bianka2112 Jun 18, 2025
d66e867
edit, delete fx, auth token added
Bianka2112 Jun 18, 2025
a7d1bc0
welcome user msg, needs styling
Bianka2112 Jun 18, 2025
04006c6
add yours feature to user posts, close edit paths
Bianka2112 Jun 18, 2025
f190a55
welcome user fix username, styling and codecleanup
Bianka2112 Jun 18, 2025
da34de8
update api url to load correct url, added all new paths, update fetches
Bianka2112 Jun 18, 2025
935a74f
update edit/del to pop snackbar confirmation
Bianka2112 Jun 18, 2025
a96ef86
Update README.md
Bianka2112 Jun 18, 2025
a71d969
frontend validate password
Bianka2112 Jun 18, 2025
d49c312
readme api doc
Bianka2112 Jun 18, 2025
24800a4
create theme provider
Bianka2112 Jun 19, 2025
d6648b6
fix terrible gray focus on btns with global mui style
Bianka2112 Jun 19, 2025
c428e6f
hid light/dark toggle btn, until all styled-comps refactored
Bianka2112 Jun 19, 2025
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ pnpm-debug.log*
lerna-debug.log*

node_modules
.env
dist
dist-ssr
*.local
package-lock.json
todo.md

# Editor directories and files
.vscode/*
Expand Down
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,45 @@
# Happy Thoughts
![Made with React](https://img.shields.io/badge/React-2023-blue?logo=react)
![Node.js](https://img.shields.io/badge/Node.js-API-green?logo=node.js)
![MongoDB](https://img.shields.io/badge/MongoDB-Mongoose-brightgreen?logo=mongodb)
![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)
![Status](https://img.shields.io/badge/status-In_Progress-yellow)

# 💬 Happy Thoughts

A social message board app where users can share short positive thoughts, ❤️ like others', and edit/delete their own posts. Built with full CRUD functionality and user authentication.

---

## 🔗 **Project Access**:

🚀 [Live Demo](https://happy-thoughts-blr.netlify.app)
📚 [View API Documentation](https://your-api.onrender.com/)

## 🛠 Technologies Used

- Frontend: React, Vite, Zustand (state management), MUI (Material UI)
- Backend: Node.js, Express, MongoDB, Mongoose
- Auth: Access tokens with protected routes and user-based permissions

---

## 💡 Features

- Register or log in to post a thought
- Like others' thoughts ❤️
- See your own thoughts marked as `"✨ Yours"`
- Edit or delete your own posts
- Logout safely with feedback via Snackbar

---

## 📌 Future Improvements

- 🌈 Add Lottie animation in the header
- 🌓 Theme toggle (dark/light mode)
- 🗂️ Paginate thoughts or infinite scroll
- 🔐 Expiring access tokens or JWT

### 🤝 Contributing

Got ideas or want to improve the app? Fork the repo, create a branch, and open a PR!
24 changes: 18 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="A cheerful app where people share and celebrate positive thoughts."
/>
<!-- Theme Color for Mobile Browsers -->
<meta name="theme-color" content="#ffffff" />
<!-- Prefetch for Faster Loading -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;700&family=Quicksand:wght@400;600&display=swap"
rel="stylesheet"
/>

<link rel="icon" type="image/png" href="/happy.cloud.png" />
<title>Happy Thoughts</title>
</head>

<body>
<div id="root"></div>
<script
type="module"
src="./src/main.jsx">
</script>
<main id="root" role="main" aria-label="Happy Thoughts App"></main>
<script type="module" src="./src/main.jsx"></script>
</body>
</html>
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,24 @@
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^7.1.1",
"@mui/material": "^7.1.1",
"dotenv": "^16.5.0",
"moment": "^2.30.1",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"react-dom": "^19.0.0",
"react-icons": "^5.5.0",
"styled-components": "^6.1.17",
"zustand": "^5.0.5"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"@vitejs/plugin-react": "^4.4.1",
"babel-plugin-styled-components": "^2.1.4",
"eslint": "^9.21.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
Expand Down
Binary file added public/happy.cloud.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/pixel-heart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
Please include your Netlify link here.
Please include your Netlify link here.

Deployed site: https://happy-thoughts-blr.netlify.app/

Github: https://github.com/Bianka2112/js-project-happy-thoughts
27 changes: 25 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
export const App = () => {
import { useEffect } from "react"
import Form from "../src/sections/Form"
import Header from "../src/sections/Header"
import { Loader } from "./components/Loader"
import { GlobalStyle } from "./GlobalStyles"
import { MsgBoard } from "./sections/MsgBoard"
import { useThoughtStore } from "./store/useThoughtStore"

const App = ({ toggleTheme, mode }) => {

const fetchThoughts = useThoughtStore((state) => state.fetchThoughts)
const loading = useThoughtStore((state) => state.loading)

useEffect(() => {
fetchThoughts()
}, [fetchThoughts])

return (
<h1>Happy Thoughts</h1>
<>
<GlobalStyle />
<Header toggleTheme={toggleTheme} mode={mode}/>
<Form />
{loading ? <Loader /> : <MsgBoard />}
</>
)
}

export default App
58 changes: 58 additions & 0 deletions src/AppWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ThemeProvider as StyledThemeProvider } from "styled-components"
import { ThemeProvider as MuiThemeProvider, CssBaseline, createTheme } from "@mui/material"
import { useState, useMemo } from "react"

import App from './App.jsx'
import { lightTheme, darkTheme } from "./theme"

const AppWrapper = () => {
const [mode, setMode] = useState("light")

const styledTheme = useMemo(() => (
mode === "dark" ? darkTheme : lightTheme
), [mode])

const muiTheme = useMemo(() =>
createTheme({
palette: {
mode,
primary: { main: styledTheme.colors.primary },
background: { default: styledTheme.colors.background },
text: { primary: styledTheme.colors.text },
},
typography: {
fontFamily: styledTheme.font,
},
components: {
MuiButtonBase: {
defaultProps: {
disableRipple: true,
},
},
MuiCssBaseline: {
styleOverrides: {
"*:focus": {
outline: "none",
boxShadow: "none",
},
"button:focus-visible": {
outline: "2px solid #f95f86",
outlineOffset: "2px",
},
},
},
},
}), [styledTheme]
)

return (
<MuiThemeProvider theme={muiTheme}>
<StyledThemeProvider theme={styledTheme}>
<CssBaseline />
<App toggleTheme={() => setMode(prev => prev === "light" ? "dark" : "light")} />
</StyledThemeProvider>
</MuiThemeProvider>
)
}

export default AppWrapper
39 changes: 39 additions & 0 deletions src/GlobalStyles.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createGlobalStyle } from "styled-components";

export const GlobalStyle = createGlobalStyle`
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
margin-top: 40px;
margin-bottom: 20px;
background:
linear-gradient(
to bottom,
rgba(255, 237, 230, 0.85),
rgba(255, 237, 230, 0.3)
);
background-size: cover;
font-family: 'Quicksand', sans-serif;
font-weight: 600;
background-color: #fdfdfd;
color: #111;
}

button {
font-family: 'Comfortaa', sans-serif;
}

a {
text-decoration: none;
color: inherit;
}

*:focus-visible {
outline: 2px solid ${({ theme }) => theme.colors.primary};
outline-offset: 2px;
}
`
37 changes: 37 additions & 0 deletions src/components/BackToTop.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from "styled-components"

const BtnIcon = styled.button`
font-size: 2rem;
cursor: pointer;
border: 2px solid lightgray;
padding: 5px;
box-shadow: 2px 2px 5px #00000033;
border-radius: 20%;
left: 50%;
margin: 0 auto;


&:hover {
border: 2px solid gray;
scale: 1.1;
}

`

const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: "smooth" })
}

const BackToTop = () => {
return (
<>
<BtnIcon
type="button"
onClick={scrollToTop}>
🔝
</BtnIcon>
</>
)
}

export default BackToTop
80 changes: 80 additions & 0 deletions src/components/DeleteButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useState } from "react"
import { useThoughtStore } from "../store/useThoughtStore"
import { useAuthStore } from "../store/useAuthStore"
import {
IconButton,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Snackbar,
Alert,
Tooltip,
} from "@mui/material"

const DeleteThought = ({ id }) => {
const deleteThought = useThoughtStore((state) => state.deleteThought)
const accessToken = useAuthStore((state) => state.accessToken)
const [openConfirm, setOpenConfirm] = useState(false)
const [snackbarOpen, setSnackbarOpen] = useState(false)

const handleDelete = async () => {
try {
await deleteThought(id)
setOpenConfirm(false)
setSnackbarOpen(true)
} catch (error) {
console.error("Failed to delete thought:", error)
}
}

if (!accessToken) return null

return (
<>
<Tooltip title="Delete">
<IconButton onClick={() => setOpenConfirm(true)} aria-label="Delete your thought">
🗑️
</IconButton>
</Tooltip>

<Dialog open={openConfirm} onClose={() => setOpenConfirm(false)}>
<DialogTitle>Confirm Deletion</DialogTitle>
<DialogContent>
Are you sure you want to delete this thought? This action can't be undone.
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenConfirm(false)} color="primary">
Cancel
</Button>
<Button
onClick={handleDelete}
color="error"
variant="contained"
sx={{ fontWeight: "bold" }}
>
Yes, Delete
</Button>
</DialogActions>
</Dialog>

<Snackbar
open={snackbarOpen}
autoHideDuration={3000}
onClose={() => setSnackbarOpen(false)}
anchorOrigin={{ vertical: "top", horizontal: "center" }}
>
<Alert
onClose={() => setSnackbarOpen(false)}
severity="success"
sx={{ width: "100%" }}
>
💭 Thought deleted successfully.
</Alert>
</Snackbar>
</>
)
}

export default DeleteThought
Loading