some css fix and websocket fix for item update
This commit is contained in:
698
package-lock.json
generated
698
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
|||||||
"@types/react": "^19.2.5",
|
"@types/react": "^19.2.5",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
|
"baseline-browser-mapping": "^2.9.19",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
|
|||||||
58
src/App.css
58
src/App.css
@@ -1,42 +1,36 @@
|
|||||||
#root {
|
#root {
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2rem;
|
padding: .5rem;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.app {
|
||||||
height: 6em;
|
display: flex;
|
||||||
padding: 1.5em;
|
flex-direction: column;
|
||||||
will-change: filter;
|
gap: 1.5rem;
|
||||||
transition: filter 300ms;
|
|
||||||
}
|
|
||||||
.logo:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #646cffaa);
|
|
||||||
}
|
|
||||||
.logo.react:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes logo-spin {
|
.user-btn {
|
||||||
from {
|
position: fixed;
|
||||||
transform: rotate(0deg);
|
top: 12px;
|
||||||
}
|
right: 12px;
|
||||||
to {
|
z-index: 1000;
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
.log-menu {
|
||||||
a:nth-of-type(2) .logo {
|
position: fixed;
|
||||||
animation: logo-spin infinite 20s linear;
|
top: 50px;
|
||||||
}
|
right: 12px;
|
||||||
|
width: 280px;
|
||||||
|
background: #111;
|
||||||
|
border: 1px solid #333;
|
||||||
|
padding: 12px;
|
||||||
|
z-index: 1001;
|
||||||
|
box-shadow: 0 8px 30px rgba(0,0,0,.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.log-menu button,
|
||||||
padding: 2em;
|
.log-menu input {
|
||||||
}
|
width: 100%;
|
||||||
|
margin-bottom: 8px;
|
||||||
.read-the-docs {
|
}
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
132
src/App.jsx
132
src/App.jsx
@@ -8,6 +8,8 @@ import { API_BASE } from './config.js'
|
|||||||
|
|
||||||
import Login from './components/login.jsx'
|
import Login from './components/login.jsx'
|
||||||
import MainApp from './components/MainApp.jsx'
|
import MainApp from './components/MainApp.jsx'
|
||||||
|
import AdminWidget from './components/widget/adminWidget.jsx'
|
||||||
|
|
||||||
|
|
||||||
export const ClientContext = createContext(null);
|
export const ClientContext = createContext(null);
|
||||||
|
|
||||||
@@ -22,9 +24,8 @@ export default function App() {
|
|||||||
const [updateCurrentPassword, setUpdateCurrentPassword] = useState("");
|
const [updateCurrentPassword, setUpdateCurrentPassword] = useState("");
|
||||||
const [updateNewPassword, setUpdateNewPassword] = useState("");
|
const [updateNewPassword, setUpdateNewPassword] = useState("");
|
||||||
|
|
||||||
const accessToken = localStorage.getItem("access_tokens");
|
|
||||||
const tokens = JSON.parse(accessToken)
|
const [logMenuOpen, setLogMenuOpen] = useState(false)
|
||||||
const accessTokenSingle = tokens[0];
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -60,6 +61,7 @@ async function checkAuth() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function logoutUser() {
|
async function logoutUser() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -87,6 +89,7 @@ async function logoutUser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function logoutAllSessions() {
|
async function logoutAllSessions() {
|
||||||
|
if (!accessTokenSingle) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE}/auth/logout_all_devices`, {
|
const res = await fetch(`${API_BASE}/auth/logout_all_devices`, {
|
||||||
@@ -113,10 +116,68 @@ async function logoutAllSessions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RegisterUser() {
|
||||||
|
|
||||||
|
let [username, setUserName] = useState("");
|
||||||
|
let [password, setPassword] = useState("");
|
||||||
|
let [displayName, setDisplayName] = useState("");
|
||||||
|
|
||||||
|
let hotel_ids = [1];
|
||||||
|
|
||||||
|
function registerUser(username, password, hotel_ids, displayname) {
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
hotel_ids,
|
||||||
|
displayname
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Reg")
|
||||||
|
|
||||||
|
const res = fetch(`${API_BASE}/auth/register`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="CreateUserDiv">
|
||||||
|
<input
|
||||||
|
value={username}
|
||||||
|
onChange={e => setUserName(e.target.value)}
|
||||||
|
placeholder="NomDeCompte"
|
||||||
|
type="text" />
|
||||||
|
|
||||||
|
<input
|
||||||
|
value={password}
|
||||||
|
onChange={e => setPassword(e.target.value)}
|
||||||
|
placeholder="Mot de Passe"
|
||||||
|
type="text" />
|
||||||
|
|
||||||
|
<input
|
||||||
|
value={displayName}
|
||||||
|
onChange={e => setDisplayName(e.target.value)}
|
||||||
|
placeholder="Nome afficher"
|
||||||
|
type="text" />
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
registerUser(username, password, hotel_ids, displayName)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Créer l'utilisateur
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function updatePassword(e) {
|
||||||
function updatePassword(e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
//try
|
//try
|
||||||
@@ -126,7 +187,7 @@ function updatePassword(e) {
|
|||||||
newpassword : updateNewPassword
|
newpassword : updateNewPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = fetch(`${API_BASE}/auth/update_password`, {
|
const res = await fetch(`${API_BASE}/auth/update_password`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -146,33 +207,46 @@ function updatePassword(e) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button onClick={logoutUser}>disconnect</button>
|
<button className="user-btn" onClick={() => setLogMenuOpen(o => !o)}>
|
||||||
<button onClick={logoutAllSessions}>disconnect all session</button>
|
⚙️
|
||||||
|
</button>
|
||||||
|
|
||||||
<form onSubmit={updatePassword}>
|
{logMenuOpen && (
|
||||||
<input
|
<div className='log-menu'>
|
||||||
type="text"
|
<button onClick={logoutUser}>disconnect</button>
|
||||||
placeholder="Username"
|
<button onClick={logoutAllSessions}>disconnect all session</button>
|
||||||
value={updateUsername}
|
|
||||||
onChange={(e) => setUpdateUsername(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<input
|
<form onSubmit={updatePassword}>
|
||||||
type="text"
|
<h1>Update Password</h1>
|
||||||
placeholder="MDP actuel"
|
<input
|
||||||
value={updateCurrentPassword}
|
type="text"
|
||||||
onChange={(e) => setUpdateCurrentPassword(e.target.value)}
|
placeholder="Username"
|
||||||
/>
|
value={updateUsername}
|
||||||
|
onChange={(e) => setUpdateUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Nouveau MDP"
|
placeholder="MDP actuel"
|
||||||
value={updateNewPassword}
|
value={updateCurrentPassword}
|
||||||
onChange={(e) => setUpdateNewPassword(e.target.value)}
|
onChange={(e) => setUpdateCurrentPassword(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button type="submit">Uppdate</button>
|
<input
|
||||||
</form>
|
type="text"
|
||||||
|
placeholder="Nouveau MDP"
|
||||||
|
value={updateNewPassword}
|
||||||
|
onChange={(e) => setUpdateNewPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button type="submit">Uppdate</button>
|
||||||
|
</form>
|
||||||
|
<RegisterUser/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
{loggedIn ? (
|
{loggedIn ? (
|
||||||
<MainApp resClientId={clientId} />
|
<MainApp resClientId={clientId} />
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { HotelProvider, useHotel } from "./HotelContext";
|
import { HotelProvider, useHotel } from "./context/HotelContext";
|
||||||
import RoomWidget from "./widget/roomWidget"
|
import RoomWidget from "./widget/roomWidget"
|
||||||
import ChatWidget from "./widget/chatWidget"
|
import ChatWidget from "./widget/chatWidget"
|
||||||
import InventoryWidget from "./widget/inventoryWidget";
|
import InventoryWidget from "./widget/inventoryWidget";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import "./MainApp.css"
|
import "./MainApp.css"
|
||||||
import AdminWidget from "./widget/adminWidget";
|
import AdminWidget from "./widget/adminWidget";
|
||||||
|
|
||||||
export default function MainAppWrapper({resClientId}) {
|
export default function MainAppWrapper({resClientId}) {
|
||||||
const accessToken = localStorage.getItem("access_tokens");
|
const accessToken = localStorage.getItem("access_tokens");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotelProvider accessToken={accessToken} resClientId={resClientId}>
|
<HotelProvider accessToken={accessToken} resClientId={resClientId}>
|
||||||
@@ -18,25 +21,29 @@ export default function MainAppWrapper({resClientId}) {
|
|||||||
|
|
||||||
function MainApp() {
|
function MainApp() {
|
||||||
const accessToken = localStorage.getItem("access_tokens");
|
const accessToken = localStorage.getItem("access_tokens");
|
||||||
const { rooms, conversations, users } = useHotel();
|
const VIEW = {
|
||||||
|
ROOMS: "rooms",
|
||||||
|
INVENTORY: "inventory",
|
||||||
|
ADMIN: "admin",
|
||||||
|
};
|
||||||
|
|
||||||
|
const { rooms } = useHotel();
|
||||||
|
const { conversations } = useHotel();
|
||||||
|
const { users } = useHotel();
|
||||||
|
|
||||||
|
const [view, setView] = useState(VIEW.ROOMS)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "2rem" }}>
|
<div>
|
||||||
<h1>Welcome to MyHotel!</h1>
|
<div className="toolbar">
|
||||||
|
<button className="toolbutton" onClick={() => setView(VIEW.ROOMS)}>Rooms</button>
|
||||||
|
<button className="toolbutton" onClick={() => setView(VIEW.INVENTORY)}>Inventory</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Access token</h2>
|
|
||||||
<pre>{accessToken}</pre>
|
|
||||||
<h3>Rooms: {rooms.length}</h3>
|
|
||||||
<h3>Conversations: {conversations.length}</h3>
|
|
||||||
<h3>Users: {users.length}</h3>
|
|
||||||
<h2>Dashboard</h2>
|
|
||||||
<section className="main">
|
<section className="main">
|
||||||
|
{view === VIEW.ROOMS && <RoomWidget />}
|
||||||
|
{view === VIEW.INVENTORY && <InventoryWidget />}
|
||||||
<RoomWidget roomlist={rooms}/>
|
<ChatWidget convlist={conversations} />
|
||||||
<ChatWidget convlist={conversations}/>
|
|
||||||
<InventoryWidget/>
|
|
||||||
<AdminWidget/>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
.main {
|
.main {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70% 30%;
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
.main > * {
|
||||||
background-color: rgb(160, 149, 199);
|
min-width: 0; /* prevents overflow bugs */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
justify-content: space-around;
|
||||||
|
height: 10vh;
|
||||||
|
height: 5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbutton {
|
||||||
|
margin: .5rem;
|
||||||
|
height: 80%;
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {createContext, useContext,
|
|||||||
useState, useEffect,
|
useState, useEffect,
|
||||||
useRef
|
useRef
|
||||||
} from "react";
|
} from "react";
|
||||||
import { API_BASE } from "../config";
|
import { API_BASE } from "../../config";
|
||||||
|
|
||||||
const HotelContext = createContext(null);
|
const HotelContext = createContext(null);
|
||||||
|
|
||||||
@@ -16,6 +16,9 @@ export function HotelProvider({ accessToken, children, resClientId}) {
|
|||||||
const [rooms, setRooms] = useState([]);
|
const [rooms, setRooms] = useState([]);
|
||||||
const [conversations, setConversations] = useState([]);
|
const [conversations, setConversations] = useState([]);
|
||||||
const [messagesByConvId, setMessagesByConvId] = useState({});
|
const [messagesByConvId, setMessagesByConvId] = useState({});
|
||||||
|
const [items, SetItems] = useState([]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
const [usersById, setUsersById] = useState({});
|
const [usersById, setUsersById] = useState({});
|
||||||
@@ -55,7 +58,6 @@ export function HotelProvider({ accessToken, children, resClientId}) {
|
|||||||
|
|
||||||
// CHAT
|
// CHAT
|
||||||
|
|
||||||
|
|
||||||
async function createConversation(name) {
|
async function createConversation(name) {
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -278,11 +280,24 @@ export function HotelProvider({ accessToken, children, resClientId}) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "item_update": {
|
||||||
|
SetItems(prev =>
|
||||||
|
prev.map(i =>
|
||||||
|
i.id === msg.item_id
|
||||||
|
? { ...i, amount: msg.number }
|
||||||
|
: i
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "chat_message": {
|
case "chat_message": {
|
||||||
appendMessage(msg);
|
appendMessage(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn("Unhandled WS message bruuuuh:", msg);
|
console.warn("Unhandled WS message bruuuuh:", msg);
|
||||||
}
|
}
|
||||||
@@ -290,7 +305,7 @@ export function HotelProvider({ accessToken, children, resClientId}) {
|
|||||||
|
|
||||||
// --- ADMIN PORTAL ----
|
// --- ADMIN PORTAL ----
|
||||||
|
|
||||||
function registerUser(username,password,hotel_ids, displayname) {
|
function registerUser(username, password, hotel_ids, displayname) {
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
username,
|
username,
|
||||||
@@ -351,10 +366,11 @@ async function addHotelUser(user_id,hotel_ids) {
|
|||||||
if (!accessToken) return;
|
if (!accessToken) return;
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
const [roomsData, convData, usersData] = await Promise.all([
|
const [roomsData, convData, usersData, itemsData] = await Promise.all([
|
||||||
fetchRooms(),
|
fetchRooms(),
|
||||||
fetchConversations(),
|
fetchConversations(),
|
||||||
fetchHotelUsers(),
|
fetchHotelUsers(),
|
||||||
|
fetchHotelInventory(),
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -362,7 +378,7 @@ async function addHotelUser(user_id,hotel_ids) {
|
|||||||
setRooms(roomsData);
|
setRooms(roomsData);
|
||||||
setConversations(convData);
|
setConversations(convData);
|
||||||
setUsers(usersData);
|
setUsers(usersData);
|
||||||
|
SetItems(itemsData);
|
||||||
//getHotelList();
|
//getHotelList();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -370,7 +386,7 @@ async function addHotelUser(user_id,hotel_ids) {
|
|||||||
load();
|
load();
|
||||||
|
|
||||||
|
|
||||||
//console.log("USERS 2 =",usersById)
|
console.log("here are hte items" + items)
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -383,7 +399,8 @@ async function addHotelUser(user_id,hotel_ids) {
|
|||||||
//if (!accessTokenSingle || !clientId) return;
|
//if (!accessTokenSingle || !clientId) return;
|
||||||
|
|
||||||
const ws = new WebSocket(
|
const ws = new WebSocket(
|
||||||
`http://localhost:7080/auth/ws/${accessTokenSingle}`
|
`ws://localhost:7080/auth/ws/${accessTokenSingle}`
|
||||||
|
//`wss://79.137.75.155/hotel-demo/api/auth/ws/${accessTokenSingle}`
|
||||||
);
|
);
|
||||||
|
|
||||||
wsRef.current = ws;
|
wsRef.current = ws;
|
||||||
@@ -423,6 +440,7 @@ async function addHotelUser(user_id,hotel_ids) {
|
|||||||
users,
|
users,
|
||||||
usersById,
|
usersById,
|
||||||
clientId,
|
clientId,
|
||||||
|
items,
|
||||||
|
|
||||||
fetchHotelUsers,
|
fetchHotelUsers,
|
||||||
updateRoomStatus,
|
updateRoomStatus,
|
||||||
65
src/components/context/RoomContext.jsx
Normal file
65
src/components/context/RoomContext.jsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import {createContext, useContext,
|
||||||
|
useState, useEffect,
|
||||||
|
useRef } from "react";
|
||||||
|
import { API_BASE } from "../../config";
|
||||||
|
|
||||||
|
const RoomContext = createContext(null);
|
||||||
|
|
||||||
|
export function UseRoom() {
|
||||||
|
return useContext(RoomContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RoomProvider({ accessToken, children, resclientid}) {
|
||||||
|
|
||||||
|
const [rooms, setRooms] = useState([]);
|
||||||
|
|
||||||
|
async function fetchRooms() {
|
||||||
|
const res = await fetch( `${API_BASE}/rooms/rooms`, {
|
||||||
|
headers: { Authorization: `Bearer ${accessTokenSingle}` },
|
||||||
|
});
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateRoomStatus(roomId, status) {
|
||||||
|
await fetch(`${API_BASE}/rooms/clean_db_update/${roomId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessTokenSingle}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ status }),
|
||||||
|
});
|
||||||
|
// refresh cached rooms
|
||||||
|
//const updated = await fetchRooms();
|
||||||
|
//setRooms(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: update room status function
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!accessToken) return;
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
const [roomsData] = await Promise.all([
|
||||||
|
fetchRooms()
|
||||||
|
]);
|
||||||
|
|
||||||
|
setRooms(roomsData);
|
||||||
|
}
|
||||||
|
|
||||||
|
load();
|
||||||
|
})
|
||||||
|
|
||||||
|
return(
|
||||||
|
<RoomContext.Provider
|
||||||
|
value={{
|
||||||
|
rooms,
|
||||||
|
|
||||||
|
|
||||||
|
updateRoomStatus
|
||||||
|
}}
|
||||||
|
></RoomContext.Provider>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -40,22 +40,104 @@ export default function Login({ onLogin }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: add login button for test1 and test2
|
||||||
|
|
||||||
|
async function LoginTest1() {
|
||||||
|
//e.preventDefault();
|
||||||
|
//setError("");
|
||||||
|
|
||||||
|
const device_id = "147ac10b-58cc-4372-a567-0e02b2c3d479";
|
||||||
|
|
||||||
|
let username = "test1"
|
||||||
|
let password = "test1"
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/auth/create_refresh`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "react-app",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify({ username, password, device_id }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
setError("Invalid credentials or server error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const data = await res.json(); // server returns short-lived token
|
||||||
|
//localStorage.setItem("access_token", data.access_token);
|
||||||
|
|
||||||
|
if (onLogin) await onLogin(); // notify App to show MainApp
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
setError("Network error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function LoginTest2() {
|
||||||
|
//e.preventDefault();
|
||||||
|
//setError("");
|
||||||
|
|
||||||
|
const device_id = "147ac10b-58cc-4372-a567-0e02b2c3d479";
|
||||||
|
|
||||||
|
let username = "test2"
|
||||||
|
let password = "test2"
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/auth/create_refresh`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "react-app",
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify({ username, password, device_id }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
setError("Invalid credentials or server error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const data = await res.json(); // server returns short-lived token
|
||||||
|
//localStorage.setItem("access_token", data.access_token);
|
||||||
|
|
||||||
|
if (onLogin) await onLogin(); // notify App to show MainApp
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
setError("Network error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<>
|
||||||
<input
|
<form onSubmit={handleSubmit}>
|
||||||
type="text"
|
<input
|
||||||
placeholder="Username"
|
type="text"
|
||||||
value={username}
|
placeholder="Username"
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
value={username}
|
||||||
/>
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
<input
|
/>
|
||||||
type="password"
|
<input
|
||||||
placeholder="Password"
|
type="password"
|
||||||
value={password}
|
placeholder="Password"
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
value={password}
|
||||||
/>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
<button type="submit">Login</button>
|
/>
|
||||||
{error && <p style={{ color: "red" }}>{error}</p>}
|
<button type="submit">Login</button>
|
||||||
</form>
|
{error && <p style={{ color: "red" }}>{error}</p>}
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
|
<button onClick={LoginTest1} >login test 1</button>
|
||||||
|
<button onClick={LoginTest2} >login test 2</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,34 @@
|
|||||||
.messagebox{
|
|
||||||
|
|
||||||
|
/* Room grid */
|
||||||
|
.roomGrid {
|
||||||
|
margin: 5px;
|
||||||
|
height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: var(--card) ;
|
||||||
|
display: grid;
|
||||||
|
padding: 16px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Room card */
|
||||||
|
.card {
|
||||||
|
background-color: var(--panel) ;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* your messages */
|
.roomCard input {
|
||||||
.msg--mine {
|
width: 100%;
|
||||||
align-self: flex-end;
|
|
||||||
background-color: #464b43;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* others */
|
|
||||||
.msg--theirs {
|
|
||||||
align-self: flex-start;
|
|
||||||
background-color: #473f3f;
|
|
||||||
}
|
|
||||||
.grid {
|
|
||||||
display: flex;
|
|
||||||
justify-items: space-around;
|
|
||||||
gap: 1px;
|
|
||||||
background-color: #777777;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
gap: 1px;
|
|
||||||
background-color: #a3a3a3;
|
|
||||||
padding: 5px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.card input {
|
|
||||||
width: 90%;
|
|
||||||
box-sizing: border-box; /* important */
|
|
||||||
max-width: 100%; /* prevents overflow */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
import { useHotel } from "../HotelContext";
|
import { useHotel } from "../context/HotelContext";
|
||||||
|
|
||||||
|
|
||||||
export default function AdminWidget() {
|
export default function AdminWidget() {
|
||||||
|
|||||||
@@ -1,16 +1,89 @@
|
|||||||
.chatWidget{
|
.chatWidget {
|
||||||
display: flex;
|
margin :5px;
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
flex-direction: column;
|
||||||
.convcard {
|
background: var(--card);
|
||||||
background-color: brown;
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.convlist {
|
.convlist {
|
||||||
|
display: flex;
|
||||||
display: flex;
|
flex-direction: row;
|
||||||
flex-direction: row;
|
gap: 0.5rem;
|
||||||
align-items: right;
|
padding: 0.75rem;
|
||||||
background-color: darkcyan;
|
overflow-y: auto;
|
||||||
|
height: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.convcard {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background: var(--panel);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.convcard:hover {
|
||||||
|
background: var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderBox{
|
||||||
|
display: flex;
|
||||||
|
height: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderBox * {
|
||||||
|
border: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.textbox{
|
||||||
|
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sendbutton{
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.messageCard {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
background: var(--messageCard);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages */
|
||||||
|
.msg {
|
||||||
|
max-width: 70%;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg--mine {
|
||||||
|
align-self: flex-end;
|
||||||
|
background: var(--accent);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg--theirs {
|
||||||
|
align-self: flex-start;
|
||||||
|
background: var(--panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
.createConvBox {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createConvBox > * {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useHotel } from "../HotelContext";
|
|
||||||
|
import { useHotel } from "../context/HotelContext";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
@@ -110,17 +111,63 @@ function SenderBox({ conv_id, onSend, disabled }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div hidden={disabled} className="senderbox">
|
<div hidden={disabled} className="senderBox">
|
||||||
<input
|
<input
|
||||||
|
className="textbox"
|
||||||
value={text}
|
value={text}
|
||||||
onChange={e => setText(e.target.value)}
|
onChange={e => setText(e.target.value)}
|
||||||
|
onKeyDown={e => e.key === "Enter" && handleSend() }
|
||||||
placeholder="Type a message…"
|
placeholder="Type a message…"
|
||||||
/>
|
/>
|
||||||
<button onClick={handleSend}>Send</button>
|
<button className="sendbutton" onClick={handleSend}>Send</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ConvCard({id, title, onOpenConv}) {
|
||||||
|
return(
|
||||||
|
<div className="convcard" onClick={() => onOpenConv(id)} >
|
||||||
|
<h3>ConvId : {id} </h3>
|
||||||
|
<h3>Name : {title}</h3>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function MessagesBox({ conv_id }) {
|
||||||
|
const { messagesByConvId, usersById, clientId } = useHotel();
|
||||||
|
const messages = messagesByConvId[conv_id] ?? [];
|
||||||
|
|
||||||
|
console.log(messagesByConvId);
|
||||||
|
console.log(usersById);
|
||||||
|
|
||||||
|
if (messages.length === 0) {
|
||||||
|
return <div className="messagesbox empty">No messages</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="messageCard">
|
||||||
|
{messages
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => new Date(a.sent_at) - new Date(b.sent_at))
|
||||||
|
.map(msg => {
|
||||||
|
const isMine = msg.sender_id === clientId;
|
||||||
|
return (
|
||||||
|
<div key={msg.sent_at}
|
||||||
|
className={`msg ${isMine ? "msg--mine" : "msg--theirs"}`}>
|
||||||
|
<p>
|
||||||
|
<strong>Sender:</strong>{" "}
|
||||||
|
{usersById[msg.sender_id] ?? "Unknown user"}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>{msg.content}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function AddUsersMenu({ convId, usersById, fetchConvUsers, onValidate, onClose }) {
|
function AddUsersMenu({ convId, usersById, fetchConvUsers, onValidate, onClose }) {
|
||||||
const [selected, setSelected] = useState(new Set());
|
const [selected, setSelected] = useState(new Set());
|
||||||
|
|
||||||
@@ -197,53 +244,10 @@ function CreateConvMenu({onSend}) {
|
|||||||
<input
|
<input
|
||||||
value= {nameText}
|
value= {nameText}
|
||||||
onChange= {element => setNameText(element.target.value)}
|
onChange= {element => setNameText(element.target.value)}
|
||||||
|
onKeyDown={e => e.key === "Enter" && handleSend() }
|
||||||
placeholder="Ma Conversation"
|
placeholder="Ma Conversation"
|
||||||
/>
|
/>
|
||||||
<button onClick= {handleSend}>Send</button>
|
<button onClick= {handleSend}>Send</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConvCard({id, title, onOpenConv}) {
|
|
||||||
return(
|
|
||||||
<div className="convcard">
|
|
||||||
<h3>ConvId : {id} </h3>
|
|
||||||
<h3>Name : {title}</h3>
|
|
||||||
<p onClick={() => onOpenConv(id)}> GET MESSAAGE</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function MessagesBox({ conv_id }) {
|
|
||||||
const { messagesByConvId, usersById, clientId } = useHotel();
|
|
||||||
const messages = messagesByConvId[conv_id] ?? [];
|
|
||||||
|
|
||||||
console.log(messagesByConvId);
|
|
||||||
console.log(usersById);
|
|
||||||
|
|
||||||
if (messages.length === 0) {
|
|
||||||
return <div className="messagesbox empty">No messages</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="messagebox">
|
|
||||||
{messages
|
|
||||||
.slice()
|
|
||||||
.sort((a, b) => new Date(a.sent_at) - new Date(b.sent_at))
|
|
||||||
.map(msg => {
|
|
||||||
const isMine = msg.sender_id === clientId;
|
|
||||||
return (
|
|
||||||
<div key={msg.sent_at}
|
|
||||||
className={`msg ${isMine ? "msg--mine" : "msg--theirs"}`}>
|
|
||||||
<p>
|
|
||||||
<strong>Sender:</strong>{" "}
|
|
||||||
{usersById[msg.sender_id] ?? "Unknown user"}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>{msg.content}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,2 +1,23 @@
|
|||||||
|
|
||||||
|
.grid {
|
||||||
|
margin: 5px ;
|
||||||
|
align-items: start;
|
||||||
|
grid-auto-rows: max-content;
|
||||||
|
height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: var(--card) ;
|
||||||
|
padding: 16px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemcard {
|
||||||
|
background-color: var(--panel) ;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
@@ -1,54 +1,46 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {HotelProvider, useHotel} from "../HotelContext";
|
import {HotelProvider, useHotel} from "../context/HotelContext";
|
||||||
|
import "./inventoryWidget.css";
|
||||||
|
|
||||||
export default function InventoryWidget({}) {
|
export default function InventoryWidget({}) {
|
||||||
const {
|
//const { fetchHotelInventory } = useHotel();
|
||||||
fetchHotelInventory
|
//const [items, setItems] = useState([]);
|
||||||
} = useHotel();
|
|
||||||
|
|
||||||
const [items, setItems] = useState([]);
|
/*
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
async function loadInventory() {
|
async function loadInventory() {
|
||||||
const data = await fetchHotelInventory()
|
const data = await fetchHotelInventory()
|
||||||
setItems(data);
|
setItems(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadInventory()
|
loadInventory()
|
||||||
console.log ("loaded inventory")
|
console.log ("loaded inventory")
|
||||||
|
|
||||||
}, [])
|
}, [])
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { items } = useHotel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<div className="grid">
|
|
||||||
{items.map(item => (
|
|
||||||
<ItemCard
|
|
||||||
key={item.id}
|
|
||||||
id={item.id}
|
|
||||||
name={item.name}
|
|
||||||
amount={item.amount}
|
|
||||||
/>
|
|
||||||
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<CreateItemMenu/>
|
<div className="grid">
|
||||||
</div>
|
{items.map(item => (
|
||||||
|
<ItemCard
|
||||||
</div>
|
key={item.id}
|
||||||
|
id={item.id}
|
||||||
|
name={item.name}
|
||||||
|
amount={item.amount}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<CreateItemMenu/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ItemCard({id, name, amount}) {
|
function ItemCard({id, name, amount}) {
|
||||||
const [itemAmount, setItemAmount] = useState(amount);
|
const [itemAmount, setItemAmount] = useState(amount);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
|
|
||||||
const {updateItemAmount} = useHotel();
|
const {updateItemAmount} = useHotel();
|
||||||
|
|
||||||
function submit(item_id, item_amount) {
|
function submit(item_id, item_amount) {
|
||||||
@@ -59,10 +51,12 @@ function ItemCard({id, name, amount}) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="itemcard">
|
<div className="itemcard">
|
||||||
<div>{name}</div>
|
<h3>{name}</h3>
|
||||||
|
|
||||||
{!editing ?(
|
{!editing ?(
|
||||||
<p onClick={() => setEditing(true)} /*style={ cursor: "pointer" }*/>Amount :{amount}</p>
|
<h5 onClick={() => setEditing(true)} >
|
||||||
|
Amount :{amount}
|
||||||
|
</h5>
|
||||||
):(
|
):(
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
@@ -74,10 +68,8 @@ function ItemCard({id, name, amount}) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: same pb as convlist, update when typing in the create menu
|
//TODO: same pb as convlist, update when typing in the create menu
|
||||||
@@ -86,25 +78,23 @@ function CreateItemMenu() {
|
|||||||
const [itemAmount, setItemAmount] = useState(0);
|
const [itemAmount, setItemAmount] = useState(0);
|
||||||
const {createItem} = useHotel();
|
const {createItem} = useHotel();
|
||||||
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!itemName.trim() | !itemAmount.trim() ) return;
|
if (!itemName.trim() | !itemAmount.trim() ) return;
|
||||||
|
|
||||||
createItem(itemName, itemAmount);
|
createItem(itemName, itemAmount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div className="itemcard" >
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={element => setItemName(element.target.value)}
|
onChange={element => setItemName(element.target.value)}
|
||||||
placeholder="Nom de l'objet"
|
placeholder="Nom de l'objet"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={element => setItemAmount(element.target.value)}
|
onChange={element => setItemAmount(element.target.value)}
|
||||||
placeholder="Montant d'objet(s)"
|
placeholder="Montant d'objet(s)"
|
||||||
/>
|
/>
|
||||||
<button onClick={handleSubmit}>Creer</button>
|
<button onClick={handleSubmit}>Creer</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
|
|
||||||
import "./RoomWidget.css";
|
import "./RoomWidget.css";
|
||||||
import { useHotel } from "../HotelContext";
|
import { useHotel } from "../context/HotelContext";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
export default function RoomWidget({ roomlist }) {
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function RoomWidget({}) {
|
||||||
|
|
||||||
|
const { rooms } = useHotel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid">
|
<div className="roomGrid">
|
||||||
{roomlist.map(room => (
|
{rooms.map(room => (
|
||||||
<RoomCard
|
<RoomCard
|
||||||
key={room.id}
|
key={room.id}
|
||||||
id = {room.id}
|
id = {room.id}
|
||||||
@@ -19,8 +24,6 @@ export default function RoomWidget({ roomlist }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RoomCard({ number, status ,id}) {
|
function RoomCard({ number, status ,id}) {
|
||||||
|
|
||||||
|
|
||||||
//FIXME: this shouldn't use hotel context, instead : set the state once on load
|
//FIXME: this shouldn't use hotel context, instead : set the state once on load
|
||||||
const { updateRoomStatus } = useHotel();
|
const { updateRoomStatus } = useHotel();
|
||||||
const [editing, setEdtiting] = useState(false);
|
const [editing, setEdtiting] = useState(false);
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
//export const API_BASE = "http://79.137.75.155:8080";
|
//export const API_BASE = "https://79.137.75.155/hotel-demo/api/";
|
||||||
export const API_BASE = "http://localhost:7080";
|
export const API_BASE = "http://localhost:7080";
|
||||||
|
|
||||||
|
|
||||||
|
//export const API_BASE = "https://79.137.75.155:5090";
|
||||||
@@ -1,68 +1,45 @@
|
|||||||
:root {
|
:root {
|
||||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
--bg: #0f172a;
|
||||||
line-height: 1.5;
|
--panel: #111827;
|
||||||
font-weight: 400;
|
--card: #1f2933;
|
||||||
|
--messageCard: #2f3f4e;
|
||||||
|
--border: #2d3748;
|
||||||
|
--text: #e5e7eb;
|
||||||
|
--muted: #9ca3af;
|
||||||
|
--accent: #6366f1;
|
||||||
|
--danger: #ef4444;
|
||||||
|
--success: #22c55e;
|
||||||
|
|
||||||
color-scheme: light dark;
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
color: rgba(255, 255, 255, 0.87);
|
|
||||||
background-color: #242424;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
padding: 0px;
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
background-color: var(--border);
|
||||||
place-items: center;
|
color: var(--text);
|
||||||
min-width: 320px;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border-radius: 8px;
|
background: var(--accent);
|
||||||
border: 1px solid transparent;
|
color: white;
|
||||||
padding: 0.6em 1.2em;
|
border: none;
|
||||||
font-size: 1em;
|
padding: 0.5rem 1rem;
|
||||||
font-weight: 500;
|
border-radius: 6px;
|
||||||
font-family: inherit;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
button:hover {
|
||||||
:root {
|
opacity: 0.9;
|
||||||
color: #213547;
|
}
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
input {
|
||||||
a:hover {
|
width: 80%;
|
||||||
color: #747bff;
|
background: var(--panel);
|
||||||
}
|
border: 1px solid var(--border);
|
||||||
button {
|
color: var(--text);
|
||||||
background-color: #f9f9f9;
|
padding: 0.5rem;
|
||||||
}
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,7 @@ import react from '@vitejs/plugin-react'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|
||||||
|
base: './',
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user