mirror of
https://framagit.org/JonathanMM/sutom.git
synced 2024-06-10 09:52:13 +02:00
Ajout option pour exporter les statistiques
This commit is contained in:
parent
51e43bf38c
commit
d2f035b1ef
|
@ -397,16 +397,16 @@ h1 {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
#fin-de-partie-panel-resume-bouton {
|
||||
.bouton-partage {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#fin-de-partie-panel-resume-bouton-icone {
|
||||
.bouton-partage svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#fin-de-partie-panel-resume-bouton-texte {
|
||||
.bouton-partage-texte {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
@ -415,6 +415,14 @@ h1 {
|
|||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
#config-sauvegarde-area {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#config-sauvegarde-area p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
#contenu {
|
||||
margin-left: 2px;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { ClavierDisposition } from "./entites/clavierDisposition";
|
|||
import Input from "./input";
|
||||
import ThemeManager from "./themeManager";
|
||||
import { Theme } from "./entites/theme";
|
||||
import CopieHelper from "./copieHelper";
|
||||
|
||||
export default class ConfigurationPanel {
|
||||
private readonly _panelManager: PanelManager;
|
||||
|
@ -128,6 +129,8 @@ export default class ConfigurationPanel {
|
|||
)
|
||||
);
|
||||
|
||||
contenu.appendChild(this.genererZoneExportSauvegarde());
|
||||
|
||||
this._panelManager.setContenuHtmlElement(titre, contenu);
|
||||
this._panelManager.setClasses(["config-panel"]);
|
||||
this._panelManager.afficherPanel();
|
||||
|
@ -160,6 +163,52 @@ export default class ConfigurationPanel {
|
|||
return div;
|
||||
}
|
||||
|
||||
private genererZoneExportSauvegarde(): HTMLElement {
|
||||
let div = document.createElement("div");
|
||||
div.id = "config-sauvegarde-area";
|
||||
|
||||
const titreSection = document.createElement("h3");
|
||||
titreSection.innerText = "Exporter vos statistiques";
|
||||
div.appendChild(titreSection);
|
||||
|
||||
const explication = document.createElement("p");
|
||||
explication.innerText = "Pour transférer vos statistiques sur un autre navigateur, il est possible de suivre les étapes suivantes :";
|
||||
div.appendChild(explication);
|
||||
|
||||
const listeEtape = document.createElement("ol");
|
||||
|
||||
const etape1 = document.createElement("li");
|
||||
|
||||
const etape1Texte = document.createElement("p");
|
||||
etape1Texte.innerText = "Copiez ce lien à usage unique.";
|
||||
etape1.appendChild(etape1Texte);
|
||||
|
||||
const etape1Input = document.createElement("input");
|
||||
const contenuLien = Sauvegardeur.genererLien();
|
||||
const lien = window.location.origin + window.location.pathname + "#" + btoa("s=" + contenuLien);
|
||||
etape1Input.value = lien;
|
||||
etape1Input.readOnly = true;
|
||||
etape1.appendChild(etape1Input);
|
||||
|
||||
const etape1Bouton = CopieHelper.creerBoutonPartage("config-sauvegarde-bouton");
|
||||
CopieHelper.attacheBoutonCopieLien(etape1Bouton, lien, "Lien copié dans le presse papier.");
|
||||
etape1.appendChild(etape1Bouton);
|
||||
|
||||
listeEtape.appendChild(etape1);
|
||||
|
||||
const etape2 = document.createElement("li");
|
||||
etape2.innerText = "Envoyez le lien vers votre autre appareil.";
|
||||
listeEtape.appendChild(etape2);
|
||||
|
||||
const etape3 = document.createElement("li");
|
||||
etape3.innerText = "Ouvrez ce lien dans votre autre navigateur.";
|
||||
listeEtape.appendChild(etape3);
|
||||
|
||||
div.appendChild(listeEtape);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
public setInput(input: Input): void {
|
||||
this._input = input;
|
||||
}
|
||||
|
|
54
ts/copieHelper.ts
Normal file
54
ts/copieHelper.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import NotificationMessage from "./notificationMessage";
|
||||
|
||||
export default class CopieHelper {
|
||||
public static attacheBoutonCopieLien(bouton: HTMLElement, lien: string, messageSucces: string): void {
|
||||
bouton.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
new Promise((resolve, reject) => {
|
||||
if (window.navigator.clipboard !== undefined) {
|
||||
return resolve(window.navigator.clipboard.writeText(lien));
|
||||
}
|
||||
|
||||
return reject();
|
||||
})
|
||||
.catch(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (window.navigator.share !== undefined) return resolve(navigator.share({ text: lien }));
|
||||
|
||||
return reject();
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
NotificationMessage.ajouterNotificationPanel(messageSucces, bouton);
|
||||
})
|
||||
.catch((raison) => {
|
||||
NotificationMessage.ajouterNotificationPanel("Votre navigateur n'est pas compatible.", bouton);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static creerBoutonPartage(idBouton: string, label?: string): HTMLElement {
|
||||
const lien = document.createElement("a");
|
||||
lien.id = idBouton;
|
||||
lien.className = "bouton-partage";
|
||||
lien.href = "#";
|
||||
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
const useSvg = document.createElementNS("http://www.w3.org/2000/svg", "use") as SVGUseElement;
|
||||
useSvg.setAttribute("href", "#icone-copie");
|
||||
useSvg.setAttribute("stroke", "var(--couleur-icone)");
|
||||
useSvg.setAttribute("fill", "var(--couleur-icone)");
|
||||
svg.appendChild(useSvg);
|
||||
lien.appendChild(svg);
|
||||
|
||||
if (label) {
|
||||
const texteBouton = document.createElement("span");
|
||||
texteBouton.className = "bouton-partage-texte";
|
||||
texteBouton.innerText = label;
|
||||
lien.appendChild(texteBouton);
|
||||
}
|
||||
|
||||
return lien;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import CopieHelper from "./copieHelper";
|
||||
import Configuration from "./entites/configuration";
|
||||
import LettreResultat from "./entites/lettreResultat";
|
||||
import { LettreStatut } from "./entites/lettreStatut";
|
||||
import InstanceConfiguration from "./instanceConfiguration";
|
||||
import NotificationMessage from "./notificationMessage";
|
||||
import PanelManager from "./panelManager";
|
||||
import Sauvegardeur from "./sauvegardeur";
|
||||
|
||||
|
@ -104,31 +104,8 @@ export default class FinDePartiePanel {
|
|||
}
|
||||
|
||||
private attacherPartage(): void {
|
||||
let resumeBouton = document.getElementById("fin-de-partie-panel-resume-bouton") as HTMLElement;
|
||||
resumeBouton.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
new Promise((resolve, reject) => {
|
||||
if (window.navigator.clipboard !== undefined) {
|
||||
return resolve(window.navigator.clipboard.writeText(this._resumeTexte + "\n\nhttps://sutom.nocle.fr"));
|
||||
}
|
||||
|
||||
return reject();
|
||||
})
|
||||
.catch(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (window.navigator.share !== undefined) return resolve(navigator.share({ text: this._resumeTexte + "\n\nhttps://sutom.nocle.fr" }));
|
||||
|
||||
return reject();
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
NotificationMessage.ajouterNotificationPanel("Résumé copié dans le presse-papier.", resumeBouton);
|
||||
})
|
||||
.catch((raison) => {
|
||||
NotificationMessage.ajouterNotificationPanel("Votre navigateur n'est pas compatible.", resumeBouton);
|
||||
});
|
||||
});
|
||||
const resumeBouton = document.getElementById("fin-de-partie-panel-resume-bouton") as HTMLElement;
|
||||
CopieHelper.attacheBoutonCopieLien(resumeBouton, this._resumeTexte + "\n\nhttps://sutom.nocle.fr", "Résumé copié dans le presse papier.");
|
||||
}
|
||||
|
||||
public afficher(): void {
|
||||
|
@ -152,12 +129,10 @@ export default class FinDePartiePanel {
|
|||
Peut-être feras-tu mieux demain ? \
|
||||
</p>";
|
||||
}
|
||||
contenu += "<p>Résumé de ta partie − ";
|
||||
contenu += CopieHelper.creerBoutonPartage("fin-de-partie-panel-resume-bouton", "Partager").outerHTML;
|
||||
contenu +=
|
||||
'<p>Résumé de ta partie − \
|
||||
<a href="#" id="fin-de-partie-panel-resume-bouton"><svg id="fin-de-partie-panel-resume-bouton-icone"> \
|
||||
<use href="#icone-copie" stroke="var(--couleur-icone)" fill="var(--couleur-icone)"></use> \
|
||||
</svg> \
|
||||
<span id="fin-de-partie-panel-resume-bouton-texte">Partager</span></a></p> \
|
||||
'</p> \
|
||||
<pre id="fin-de-partie-panel-resume">' +
|
||||
this._resumeTexteLegacy +
|
||||
"</pre>";
|
||||
|
|
|
@ -15,6 +15,7 @@ import ConfigurationPanel from "./configurationPanel";
|
|||
import AudioPanel from "./audioPanel";
|
||||
import ThemeManager from "./themeManager";
|
||||
import InstanceConfiguration from "./instanceConfiguration";
|
||||
import LienHelper from "./lienHelper";
|
||||
|
||||
export default class Gestionnaire {
|
||||
private _grille: Grille | null = null;
|
||||
|
@ -83,19 +84,9 @@ export default class Gestionnaire {
|
|||
}
|
||||
|
||||
private getIdPartie(partieEnCours: PartieEnCours) {
|
||||
if (window.location.hash !== "" && window.location.hash !== "#") {
|
||||
let hashPart = atob(window.location.hash.substring(1)).split("/");
|
||||
for (let infoPos in hashPart) {
|
||||
let info = hashPart[infoPos];
|
||||
if (!info.includes("=")) continue;
|
||||
let infoPart = info.split("=");
|
||||
let infoKey = infoPart[0];
|
||||
const infoDansLocation = LienHelper.extraireInformation("p");
|
||||
|
||||
if (infoKey !== "p") continue;
|
||||
|
||||
return infoPart[1];
|
||||
}
|
||||
}
|
||||
if (infoDansLocation !== null) return infoDansLocation;
|
||||
|
||||
if (partieEnCours.idPartie !== undefined) return partieEnCours.idPartie;
|
||||
|
||||
|
@ -120,6 +111,15 @@ export default class Gestionnaire {
|
|||
}
|
||||
|
||||
private enregistrerPartieDansStats(): void {
|
||||
// On regarde si c'est le même jour que la dernière partie dans les stats.
|
||||
// Si c'est identique, on ne sauvegarde pas
|
||||
if (
|
||||
this._stats.dernierePartie.getFullYear() === this._datePartieEnCours.getFullYear() &&
|
||||
this._stats.dernierePartie.getMonth() === this._datePartieEnCours.getMonth() &&
|
||||
this._stats.dernierePartie.getDate() === this._datePartieEnCours.getDate()
|
||||
)
|
||||
return;
|
||||
|
||||
this._stats.partiesJouees++;
|
||||
let estVictoire = this._resultats.some((resultat) => resultat.every((item) => item.statut === LettreStatut.BienPlace));
|
||||
if (estVictoire) {
|
||||
|
|
19
ts/lienHelper.ts
Normal file
19
ts/lienHelper.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
export default class LienHelper {
|
||||
public static extraireInformation(cle: string): string | null {
|
||||
if (window.location.hash === "" || window.location.hash === "#") return null;
|
||||
|
||||
let hashPart = atob(window.location.hash.substring(1)).split("/");
|
||||
for (let infoPos in hashPart) {
|
||||
let info = hashPart[infoPos];
|
||||
if (!info.includes("=")) continue;
|
||||
let infoPart = info.split("=");
|
||||
let infoKey = infoPart[0];
|
||||
|
||||
if (infoKey !== cle) continue;
|
||||
|
||||
return infoPart[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ import Configuration from "./entites/configuration";
|
|||
import PartieEnCours from "./entites/partieEnCours";
|
||||
import SauvegardePartie from "./entites/sauvegardePartie";
|
||||
import SauvegardeStats from "./entites/sauvegardeStats";
|
||||
import LienHelper from "./lienHelper";
|
||||
import NotificationMessage from "./notificationMessage";
|
||||
|
||||
export default class Sauvegardeur {
|
||||
private static readonly _cleStats = "statistiques";
|
||||
|
@ -13,7 +15,21 @@ export default class Sauvegardeur {
|
|||
}
|
||||
|
||||
public static chargerSauvegardeStats(): SauvegardeStats | undefined {
|
||||
let dataStats = localStorage.getItem(this._cleStats);
|
||||
const contenuLocation = LienHelper.extraireInformation("s");
|
||||
|
||||
if (contenuLocation) {
|
||||
const donneesDepuisLien = Sauvegardeur.chargerInformationDepuisLien(contenuLocation);
|
||||
window.location.hash = "";
|
||||
if (donneesDepuisLien) {
|
||||
NotificationMessage.ajouterNotification("Statistiques chargés avec succès.");
|
||||
Sauvegardeur.sauvegarderStats(donneesDepuisLien);
|
||||
return donneesDepuisLien;
|
||||
}
|
||||
|
||||
NotificationMessage.ajouterNotification("Impossible de charger les statistiques depuis le lien.");
|
||||
}
|
||||
|
||||
const dataStats = localStorage.getItem(this._cleStats);
|
||||
if (!dataStats) return;
|
||||
|
||||
let stats = JSON.parse(dataStats) as SauvegardeStats;
|
||||
|
@ -66,4 +82,68 @@ export default class Sauvegardeur {
|
|||
let config = JSON.parse(dataConfig) as Configuration;
|
||||
return config;
|
||||
}
|
||||
|
||||
public static genererLien(): string {
|
||||
const stats = Sauvegardeur.chargerSauvegardeStats() ?? SauvegardeStats.Default;
|
||||
return [
|
||||
stats.repartition[1],
|
||||
stats.repartition[2],
|
||||
stats.repartition[3],
|
||||
stats.repartition[4],
|
||||
stats.repartition[5],
|
||||
stats.repartition[6],
|
||||
stats.repartition["-"],
|
||||
stats.lettresRepartitions.bienPlace,
|
||||
stats.lettresRepartitions.malPlace,
|
||||
stats.lettresRepartitions.nonTrouve,
|
||||
stats.dernierePartie,
|
||||
].join(",");
|
||||
}
|
||||
|
||||
private static chargerInformationDepuisLien(contenu: string): SauvegardeStats | null {
|
||||
const [
|
||||
UnCoupString,
|
||||
DeuxCoupsString,
|
||||
TroisCoupsString,
|
||||
QuatreCoupsString,
|
||||
CinqCoupsString,
|
||||
SixCoupsString,
|
||||
PerduString,
|
||||
LettresBienPlaceesString,
|
||||
LettresMalPlaceesString,
|
||||
LettresNonTrouveString,
|
||||
dernierePartie,
|
||||
] = contenu.split(",");
|
||||
|
||||
const UnCoup = parseInt(UnCoupString);
|
||||
const DeuxCoups = parseInt(DeuxCoupsString);
|
||||
const TroisCoups = parseInt(TroisCoupsString);
|
||||
const QuatreCoups = parseInt(QuatreCoupsString);
|
||||
const CinqCoups = parseInt(CinqCoupsString);
|
||||
const SixCoups = parseInt(SixCoupsString);
|
||||
const Perdu = parseInt(PerduString);
|
||||
const LettresBienPlacees = parseInt(LettresBienPlaceesString);
|
||||
const LettresMalPlacees = parseInt(LettresMalPlaceesString);
|
||||
const LettresNonTrouve = parseInt(LettresNonTrouveString);
|
||||
|
||||
return {
|
||||
dernierePartie: new Date(dernierePartie),
|
||||
partiesJouees: UnCoup + DeuxCoups + TroisCoups + QuatreCoups + CinqCoups + SixCoups + Perdu,
|
||||
partiesGagnees: UnCoup + DeuxCoups + TroisCoups + QuatreCoups + CinqCoups + SixCoups,
|
||||
repartition: {
|
||||
1: UnCoup,
|
||||
2: DeuxCoups,
|
||||
3: TroisCoups,
|
||||
4: QuatreCoups,
|
||||
5: CinqCoups,
|
||||
6: SixCoups,
|
||||
"-": Perdu,
|
||||
},
|
||||
lettresRepartitions: {
|
||||
bienPlace: LettresBienPlacees,
|
||||
malPlace: LettresMalPlacees,
|
||||
nonTrouve: LettresNonTrouve,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue