Skip to content
Open
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
4 changes: 3 additions & 1 deletion Nexia/src/Nexia/SystemAtm/screens/ConfigurationAtm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export const ConfigurationPanel = () => {
fetchUser()
}, [])


// Set theme
const handleSetTheme = (gradient: string) => {
localStorage.setItem("atmTheme", gradient)
window.dispatchEvent(new Event("themeChange"))
Expand All @@ -83,7 +85,7 @@ export const ConfigurationPanel = () => {
<div className="cfg__card">
{!user ? (
<LoadingIcon color="white" />
) : !isGoogleUser ? (
) : isGoogleUser ? (
<>
<h2>Perfil</h2>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* Icons */
import { Crown } from "lucide-react";

/* Images */
import user from "../../../../../assets/Icons/user_light.svg"

/* Utils */
import { formatValue, getMetricValue } from "../utils/leaderboard.utils";

Expand All @@ -10,7 +13,11 @@ export const TopLeaderboard = ({ top3, balance, metric }: any) => (
<>
{[1, 0, 2].map((pos, idx) => (
<div className="top-leaderboard" key={idx}>
{top3[pos]?.avatar && <img src={top3[pos].avatar} alt="User" />}
{top3[pos]?.avatar ?
<img src={top3[pos].avatar} alt="User" />
:
<img src={user} alt="User" />
}

<div className={`box-title-leaderboard-top${pos === 0 ? 1 : pos === 1 ? 2 : 3}`}>
<span className={`balance-name-leaderboard ${balance ? "in" : "out"}`}>
Expand Down
174 changes: 160 additions & 14 deletions Nexia/src/Nexia/SystemPhone/Apps/ContactApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { useEffect, useState } from "react"
/* Images */
import user from "../../../assets/Icons/user_light.svg"

/* Icons */
import { Trash } from "lucide-react"

/* Components */
import { LoadingIcon } from "../../components/loading.ldrs"

/* Services */
import { getContacts } from "../../services/external/contacts/contacts.service"
import { deleteContact, getContacts, updateContact } from "../../services/external/contacts/contacts.service"



Expand All @@ -20,6 +23,9 @@ type Contact = {
}
const ContactApp = () => {
const [data, setData] = useState<Contact[]>([])
const [editingId, setEditingId] = useState<number | null>(null)
const [editValue, setEditValue] = useState("")
const [trash, setTrash] = useState(false)

// Success send data
const [success, setSuccess] = useState(false)
Expand All @@ -31,14 +37,62 @@ const ContactApp = () => {
const [exitError, setExitError] = useState(false)



// Get contact
const fetchUser = async () => {
try {

const res = await getContacts()

setData(res.data)

} catch (error: any) {

const message =
error?.response?.data?.message ||
error?.response?.data?.error ||
error?.message ||
"Error inesperado"

setErrorMsg(message)
setError(true)
setExitError(false)

setTimeout(() => setExitError(true), 2000)

setTimeout(() => {
setError(false)
setErrorMsg(null)
}, 2300)

}
}

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


// Save contact
const saveContact = async (contact_id: number, newName: string) => {
try {

if (!newName) return null

await updateContact(contact_id, newName.trim())

// Actualización optimista
setData(prev =>
prev.map(contact =>
contact.contact_id === contact_id
? { ...contact, name_contact: newName.trim() }
: contact
)
)

setEditingId(null)
setEditValue("")


setSuccess(true)
setVisible(false)

Expand All @@ -47,7 +101,7 @@ const ContactApp = () => {

// Delete animation success
setTimeout(() => setSuccess(false), 2300)

} catch (error: any) {

const message =
Expand All @@ -69,20 +123,58 @@ const ContactApp = () => {

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


// Delete contact
const deleteCon = async (contact_id: number) => {
try {

await deleteContact(contact_id)

await fetchUser()


setSuccess(true)
setVisible(false)

// Enter animation success
setTimeout(() => setVisible(true), 2000)

// Delete animation success
setTimeout(() => setSuccess(false), 2300)

} catch (error: any) {

const message =
error?.response?.data?.message ||
error?.response?.data?.error ||
error?.message ||
"Error inesperado"

setErrorMsg(message)
setError(true)
setExitError(false)

setTimeout(() => setExitError(true), 2000)

setTimeout(() => {
setError(false)
setErrorMsg(null)
}, 2300)

}
}



return (
<>
<div className="contacts-container">

<h3 className="contacts-title">Contactos</h3>

{/* Contacts */}
<div className="contacts-list">

{data === null ? (
<div className="loading-contact">
<LoadingIcon color="black" />
Expand All @@ -93,28 +185,82 @@ const ContactApp = () => {
</p>
) : (
<>
{data.map(c => (
<div key={c.contact_id} className="contact-item">

{data.map((c) => (
<button
key={c.contact_id}
type="button"
className="contact-item"
onMouseEnter={() => setTrash(true)}
onMouseLeave={() => setTrash(false)}
>
<div className="contact-avatar">
<img src={user} alt="usuario" />
</div>

<div className="contact-info">
<h4>{c.name_contact}</h4>
{editingId === c.contact_id ? (
<input
type="text"
value={editValue}
autoFocus
onChange={(e) => setEditValue(e.target.value)}
onBlur={() => saveContact(c.contact_id, editValue)}
onKeyDown={(e) => {
if (e.key === "Enter") {
saveContact(c.contact_id, editValue)
}
if (e.key === "Escape") {
setEditingId(null)
setEditValue("")
}
}}
/>
) : (
<h4
onClick={() => {
setEditingId(c.contact_id)
setEditValue(c.name_contact)
}}
>
{c.name_contact}
</h4>
)}

<p>
{`${c.phone.slice(0, 3)} ${c.phone.slice(3, 6)} ${c.phone.slice(6, 10)}`}
</p>
</div>

</div>
{trash && (
<button
className="box-delete-contact"
onClick={() => deleteCon(c.contact_id)}
>
<Trash color="darkred" />
</button>
)}
</button>
))}
</>
)}

</div>

</div>


{/* Success */}
{success && (
<span className={`success-contact ${visible ? "exit" : ""}`}>
</span>
)}

{/* Error */}
{error && (
<div className={`error-contact ${exitError ? "exit" : ""}`}>
{errorMsg}
</div>
)}
</>
)
}
Expand Down
14 changes: 13 additions & 1 deletion Nexia/src/Nexia/SystemPhone/Apps/Settings/SettingsApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const SettingsApp = () => {
// Screens configuration render
const [options, setOptions] = useState<string>("settings")

// Search options
const [searchValue, setSearchValue] = useState("")

// Container from icons
type Options = {
id: number
Expand All @@ -70,6 +73,11 @@ const SettingsApp = () => {
{ id: 15, containImage: "settings-comments", src: comment, alt: "Comentarios", description: "Servicios y comentarios", optionRender: "services" },
]

// Filter menu options
const filteredOptions = optionsSettings.filter(v =>
v.description.toLowerCase().includes(searchValue.toLowerCase())
)



return (
Expand All @@ -88,11 +96,13 @@ const SettingsApp = () => {
className="input-app-settings"
type="text"
placeholder="Buscar en Ajustes"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
/>
</div>

<div className="box-app-screen-settings">
{optionsSettings.map((v, i) => (
{filteredOptions.map((v, i) => (
<>
<button key={v.id} className="button-app-settings-options" onClick={() => setOptions(v.optionRender)}>

Expand Down Expand Up @@ -122,6 +132,8 @@ const SettingsApp = () => {
</>
)}


{/* Menu options */}
{options === "aboutPhone" && <AboutPhone back={() => setOptions("settings")} />}
{options === "updateSystem" && <UpdateSystem back={() => setOptions("settings")} />}
{options === "securityStatus" && <SecurityStatus back={() => setOptions("settings")} />}
Expand Down
33 changes: 29 additions & 4 deletions Nexia/src/Nexia/SystemPhone/screens/screenApps.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Hooks */
import { useState, type JSX } from "react"
import { useEffect, useState, type JSX } from "react"

/* Image Apps */
import settings from "../../../assets/Apps/settings_dark.svg"
Expand Down Expand Up @@ -107,12 +107,37 @@ const Apps = () => {
// Buttons to go back
type AppKey = keyof typeof appScreens
const [openApp, setOpenApp] = useState<AppKey | null>(null)
const [visible, setVisible] = useState(false)


// Animation open and close App
useEffect(() => {
if (openApp) {
setVisible(false)

const id = setTimeout(() => {
setVisible(true)
}, 1)

return () => clearTimeout(id)
}
}, [openApp])


const goHome = () => {
setOpenApp(null)
setVisible(false)

setTimeout(() => {
setOpenApp(null)
}, 300)
}

const goBack = () => {
setOpenApp(null)
setVisible(false)

setTimeout(() => {
setOpenApp(null)
}, 300)
}


Expand All @@ -134,7 +159,7 @@ const Apps = () => {

{/* Screen apps */}
{openApp ? (
<div className="Container-apps-screens">
<div className={`container-apps-screens ${!visible ? "enter" : "exit"}`}>
{appScreens[openApp](goHome)}
</div>
) : (
Expand Down
Loading