Ajout option pour exporter les statistiques

This commit is contained in:
JonathanMM 2023-05-18 11:14:32 +02:00
parent 51e43bf38c
commit d2f035b1ef
7 changed files with 232 additions and 47 deletions

View file

@ -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;

View file

@ -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
View 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;
}
}

View file

@ -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>";

View file

@ -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
View 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;
}
}

View file

@ -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,
},
};
}
}