mardi 27 septembre 2022

React - Best practice to organize mass API-calls/models and its data/functions

Im not happy how i handle API calls and its data.

My application is downloading all needed data right after logging in and frequently asking the API for updates. If there are any updates the will be added to the data. Because all data depending on each other they all need to know each other.

I try different ways to separate each model to one js.-file but ended up creating one big file (2000 lines of code) which contains all models and its functions (login, logout, resetPasswd, insert, update, remove, getForeignObjectByID, ...). I initialize this file at the beginning(App.js) as custom hook and provide it to every child.

I think my case isn't that special, i wonder why i cant find any informations about how to manage mass models. So what is the best practise to handly stuff like this?

Here is the code. I had to cut some parts out, so some thinks doesnt make sence, dont wonder. Please focus on my question, i try to clean this up step by step.

import { useState, useEffect } from 'react';
import FormatDate from "../format.date"

export default function useData() {
const url = "https://123.123.123.123:1234/"

const [informations, setInformations] = useState([])
const [owners, setOwners] = useState([])
const [users, setUsers] = useState([])
const [services, setServices] = useState([])
const [settings, setSettings] = useState([])
const [loadingState, setLoadingState] = useState("waiting...")
const [loadingProgression, setLoadingProgression] = useState(0)

const { formatDate } = FormatDate()



useEffect(() => {
    if (!token) return
    loadData(token)
}, [token])



const login = async (credentials) => {
    const res = fetch(url + 'login',
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(credentials)
        })
        .then(data => data.json())
        .catch((error) => {
            return { success: false, error: true, errorText: "Login fehlgeschlagen" }
        })

    return await res;
}

const confirmMail = async (mail, key) => {
    const res = fetch(url + `mailConfirm?mail=${encodeURIComponent(mail)}&key=${encodeURIComponent(key)}`,
        {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }
        })
        .then(data => data.json())
        .catch((error) => {
            return { success: false, error: true, errorText: "Mail-Bestätigung fehlgeschlagen" }
        })

    return await res
}

const resetPasswortRequest = async (mail) => {
    const res = fetch(url + `resetPasswordRequest`,
        {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                "mail": mail
            })
        })
        .then(data => data.json())
        .catch((error) => {
            return { success: false, error: true, errorText: "Passwort zurücksetzen fehlgeschlagen" }
        })

    return await res
}

const resetPasswort = async (mail, password, key) => {
    const res = fetch(url + `resetPassword`,
        {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                "mail": mail,
                "password": password,
                "key": key
            })
        })
        .then(data => data.json())
        .catch((error) => {
            return { success: false, error: true, errorText: "Passwort zurücksetzen fehlgeschlagen" }
        })

    return await res
}

const registrate = async (mail, password) => {
    const res = fetch(url + 'signup',
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                "email": mail,
                "password": password,
                "key": "?"
            })
        })
        .then(data => data.json())

    return await res;
}

const loadData = async (token) => {
    setLoadingReady(false)

    setLoadingState("Lade Informationen")
    setLoadingProgression(30)
    const i = await loadInformations(token)

    setLoadingState("Lade Eigentümer")
    setLoadingProgression(50)
    const o = await loadOwners(token)

    setLoadingState("Lade Services")
    setLoadingProgression(60)
    const s = await loadServices(token)

    // setLoadingState("Lade Einstellungen")
    // setLoadingProgression(65)
    // const s2 = await loadSettings(token)

    setLoadingState("Lade Benutzer")
    setLoadingProgression(70)
    const u = await loadUsers(token)

    setLoadingProgression(80)
    setLoadingState("Verarbeite Daten")

    if (!o.error) {
        var dataOwners = convertID(o)
        setOwners(relateOwners(dataOwners))
    }

    if (!i.error) {
        var dataInformations = convertID(i)
        setInformations(relateInformations(dataInformations, ...))
    }

    if (!s.error) {
        var dataServices = convertID(s)
        setServices(dataServices)
    }

    // if (!s2.error) {
    //     setSettings(s2)
    // }

    if (!u.error) {
        var dataUsers = convertID(u)
        setUsers(dataUsers)
    }

    setLoadingProgression(100)
    setLoadingState("Fertig!")
    setLoadingReady(true)
}

//#region ########## Informations ##########

const loadInformations = async (t2) => {
    const res = await fetch(url + `informations`,
        {
            method: "GET",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + t2
            }
        })
    return await res.json()
}

const deleteInformation = async (information) => {
    return await fetch(url + `informations/${information.id}`,
        {
            method: "DELETE",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            }
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const filtered = informations.filter((el) => {
                return el.id !== information.id;
            })
            setInformations(filtered)
            return { success: true, response: information }
        } else {
            const errorText = "Information konnte nicht gelöscht werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Information konnte nicht gelöscht werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const updateInformation = async (information) => {
    ...

    return await fetch(url + `informations/${u?????.id}`,
        {
            method: "PUT",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(u?????)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const relatedInformations = relateInformations(
                informations.map((b) => b.id === information.id ? information : b), ...)

            setInformations(relatedInformations)
            return { success: true, response: information }
        } else {
            const errorText = "Information konnte nicht gespeichert werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Information konnte nicht gespeichert werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const insertInformation = async (information) => {
    var uInformation = JSON.parse(JSON.stringify(information))
    delete uInformation["?????Obj"]
    delete uInformation["_id"]
    delete uInformation["?????Index"]
    delete uInformation["x"]
    delete uInformation["y"]
    delete uInformation["height"]
    delete uInformation["width"]
    delete uInformation["domain"]

    return await fetch(url + `informations`,
        {
            method: "POST",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(uInformation)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            var newInformation = relateInformation({ ...uInformation, id: res.id }, ?????s)
            setInformations([...informations, newInformation])
            return { success: true, response: newInformation }
        } else {
            const errorText = "Information konnte nicht hinzugefügt werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Information konnte nicht hinzugefügt werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const relateInformations = (dataInformations, data?????s) => {
    var newInformations = []
    dataInformations.forEach(i => {
        var newInformation = relateInformation(i, data?????s)
        newInformations.push(newInformation)
    });

    return newInformations
}

const relateInformation = (information, data?????s) => {
    var newInformation = JSON.parse(JSON.stringify(information))

    if (newInformation.date.$date) {
        newInformation.date = formatDate(newInformation.date.$date, "yyyy-MM-dd")
    }

    if (newInformation.status) {
        switch (newInformation.status) {
            case 0:
                newInformation.statusText = "Offen"
                break;
            case 1:
                newInformation.statusText = "Erledigt"
                break;
        }
    }

    var ????? = null
    for (var i = 0; i < data?????s.length && ????? == null; i++)
        if (data?????s[i].id == newInformation.?????)
            ????? = data?????s[i]
    newInformation.?????Obj = ?????

    return newInformation
}

const emptyInformation = () => {
    return {
        text: "",
        ?????: "",
        date: formatDate(new Date(), "yyyy-MM-dd"),
        status: 0
    }
}

//#endregion

//#region ########## Owners ##########

const loadOwners = async (t2) => {
    const res = await fetch(url + "owners",
        {
            method: "GET",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + t2
            }
        })
    return await res.json()
}

const deleteOwner = async (owner) => {
    return await fetch(url + `owners/${owner.id}`,
        {
            method: "DELETE",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            }
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const filtered = owners.filter((el) => {
                return el.id !== owner.id;
            })
            setOwners(filtered)
            return { success: true, response: owner }
        } else {
            const errorText = "Eigentümer konnte nicht gelöscht werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Eigentümer konnte nicht gelöscht werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const updateOwner = async (owner) => {
    delete owner["_id"]
    delete owner["fullName"]

    return await fetch(url + `owners/${owner.id}`,
        {
            method: "PUT",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(owner)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            setOwners(owners.map((o) => o.id === owner.id ? relateOwner(owner) : o))
            return { success: true, response: owner }
        } else {
            const errorText = "Eigentümer konnte nicht gespeichert werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Eigentümer konnte nicht gespeichert werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const insertOwner = async (owner) => {
    return await fetch(url + `owners`,
        {
            method: "POST",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(owner)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            var newOwner = { ...owner, id: res.id }
            setOwners([...owners, newOwner])
            return { success: true, response: newOwner }
        } else {
            const errorText = "Eigentümer konnte nicht hinzugefügt werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Eigentümer konnte nicht hinzugefügt werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const getOwnerByID = (id) => {
    for (let i = 0; i < owners.length; i++) {
        if (owners[i].id == id) {
            return owners[i]
        }
    }
}

const relateOwners = (dataOwners) => {
    var newOwners = []
    dataOwners.forEach(o => {
        newOwners.push(relateOwner(o))
    });

    return newOwners
}

const relateOwner = (owner) => {
    var newOwner = JSON.parse(JSON.stringify(owner))
    newOwner.fullName = newOwner.firstname + " " + newOwner.lastname
    return newOwner
}

const emptyOwner = () => {
    return {
        firstname: "",
        lastname: "",
        street: "",
        zip: "",
        place: "",
        country: "",
        telefon: "",
        mail: "",
        commission: 1,
        customSalutation: false,
        salutation: ""
    }
}

//#endregion

//#region ########## Users ##########

const loadUsers = async (t2) => {
    const res = await fetch(url + "users",
        {
            method: "GET",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + t2
            }
        })
    return await res.json()
}

const insertUser = async (user) => {
    return await fetch(url + `users`,
        {
            method: "POST",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(user)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            var newUser = relateUser({ ...user, id: res.id })
            setUsers([...users, newUser])
            return { success: true, response: newUser }
        } else {
            const errorText = "Benutzer konnte nicht hinzugefügt werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Benutzer konnte nicht hinzugefügt werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const updateUser = async (user) => {
    delete user["_id"]

    return await fetch(url + `users/${user.id}`,
        {
            method: "PUT",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(user)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            setUsers(users.map((u) => u.id === user.id ? relateUser(user) : u))
            return { success: true, error: undefined, response: user }
        } else {
            const errorText = "Benutzer konnte nicht gespeichert werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Benutzer konnte nicht gespeichert werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const deleteUser = async (user) => {
    return await fetch(url + `users/${user.id}`,
        {
            method: "DELETE",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            }
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const filtered = users.filter((el) => {
                return el.id !== user.id;
            })
            setUsers(filtered)
            return { success: true, error: undefined, response: user }
        } else {
            const errorText = "Benutzer konnte nicht gelöscht werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Benutzer konnte nicht gelöscht werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const relateUsers = (dataUsers) => {
    var newUsers = []
    dataUsers.forEach(u => {
        newUsers.push(relateUser(u))
    });

    return newUsers
}

const relateUser = (dataUser) => {
    var newUser = JSON.parse(JSON.stringify(dataUser))
    return newUser
}

const emptyUser = () => {
    return {
        email: "",
        password: "",
        permissions: {
            ownerView: true,
            ownerEdit: true,
            ?????View: true,
            ?????Edit: true,
            tenantView: true,
            tenantEdit: true,
            informationView: true,
            informationEdit: true,
            serviceTemplateView: true,
            serviceTemplateEdit: true,
            userView: false,
            userEdit: false

        }
    }
}

//#endregion

//#region ########## Services ##########

const loadServices = async (t2) => {
    const res = await fetch(url + "serviceTemplates",
        {
            method: "GET",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + t2
            }
        })
    return await res.json()
}

const insertService = async (service) => {
    return await fetch(url + `serviceTemplates`,
        {
            method: "POST",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(service)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const newService = { ...service, id: res.id }
            setServices([...services, newService])
            return { success: true, error: undefined, response: newService }
        } else {
            const errorText = "Service konnte nicht hinzugefügt werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Service konnte nicht hinzugefügt werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const updateService = async (service) => {
    delete service["_id"]
    return await fetch(url + `serviceTemplates/${service.id}`,
        {
            method: "PUT",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            },
            body: JSON.stringify(service)
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            setServices(services.map((s) => s.id === service.id ? service : s))
            return { success: true, error: undefined, response: service }
        } else {
            const errorText = "Service konnte nicht gespeichert werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Service konnte nicht gespeichert werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const deleteService = async (service) => {
    return await fetch(url + `serviceTemplates/${service.id}`,
        {
            method: "DELETE",
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + token
            }
        }
    ).then((res) => {
        return res.json();
    }).then((res) => {
        if (!res.error) {
            const filtered = services.filter((el) => {
                return el.id !== service.id;
            })
            setServices(filtered)
            return { success: true, error: undefined, response: service }
        } else {
            const errorText = "Service konnte nicht gelöscht werden!\n" +
                errorTexts[parseInt(res.error)]
            return { success: false, error: res.error, errorText: errorText }
        }
    }).catch((error) => {
        const errorText = "Service konnte nicht gelöscht werden!\n" + error
        return { success: false, error: true, errorText: errorText }
    })
}

const emptyService = () => {
    return {
        name: "",
        parentType: "None",
        commission: 100,
        ?????PerPiece: 0,
        ?????Initial: 0
    }
}

//#endregion


const getCurrentDate = (days = 0) => {
    return new Date(new Date().setDate(new Date().getDate() + days))
}

return {
    data: {
        informations,
        setInformations,
        loadInformations,
        insertInformation,
        updateInformation,
        deleteInformation,
        emptyInformation,
        owners,
        setOwners,
        insertOwner,
        updateOwner,
        deleteOwner,
        getOwnerByID,
        emptyOwner,
        services,
        setServices,
        insertService,
        updateService,
        deleteService,
        emptyService,
        users,
        setUsers,
        insertUser,
        updateUser,
        deleteUser,
        emptyUser,
        loadData,
        login,
        registrate,
        confirmMail,
        resetPasswortRequest,
        resetPasswort,
        loadingState,
    }
}

}

Thaks for your time

Aucun commentaire:

Enregistrer un commentaire