Documentação Técnica Magic Tree & Kids Rock Baltimore Education

Documentação Técnica sobre o desenvolvimento da plataforma de ensino infantil

Precisa de Suporte?

Tem alguma dúvida, ou precisa de Suporte? Clique aqui para abrir um chamado técnico! É só abrir uma conta ou fazer login na nossa Central de Atendimento. Nosso prazo de atendimento para os chamados técnicos são em média de 24 horas úteis (ou três dias corridos, de seg. à sex.). Não sabe como abrir um chamado? Aqui tem um vídeo mostrando como fazer isso.

Posso enviar mensagens no WhatsAapp?

Claro! Mas note que no WhatsApp as respostas podem demorar um pouco mais dependendo do número de mensagens que tivermos recebido, mas se enviou por lá, é só aguardar que assim que possível você terá um retorno.

⚠️  Problemas para salvar os dados?

Alguns usuários estão reportando dificuldades em salvar as informações no painel do WordPress, dos plugins da Fabrica de Plugins.
Isso está acontecendo por causa da versão do Plugin Advanced Custom Fields. Para corrigir isso, faça a instalação dessa versão do Advanced Custom Fields que tudo voltará a funcionar como deveria.

Se você instalou a versão do Advanced Custom Fields, enviada no e-mail de compra do plugin, você já deve estar com a versão correta.

Se mesmo assim enfrentar dificuldades, você pode acionar o suporte, que realizaremos a instalação para você.

1 - 01. Introdução

Esse documento tem como o objetivo demonstrar como foi desenvolvido e como se estrutura as plataformas MagicTree e Kids Rock da Baltimore Education. Que apesar de serem plataformas diferentes, são plataformas irmãs e foram desenvolvidas usando a mesma tecnologia e abordagem.

O objetivo aqui não é servir de base para uma integração com outros sistemas ou plataformas, e sim apenas dar um norte sobre as estratégias adotadas e como tudo funciona. Por causa disso, não vou entrar aqui no detalhe de cada função ou end-point, vou apenas demonstrar como a estrutura geral funciona, e também, me precavendo para não expor estratégias ou regras de negócio senciveis do cliente proprietário da plataforma.

Qualquer dúvida deve ser enviada diretamente para contato@mangu.com.br ou para contato@fabricadeplugins.com.br.

Clique para carregar o vídeo

Clique para carregar o vídeo

 

2 - 02. Conhecendo a plataforma

A plataforma Kids Rock é um sistema para aprendizagem do idioma de inglês para crianças e adolescentes que são alunos da Baltimore Education. Podemos dividir a plataforma em três frentes:

  • A Área do Aluno/Área do professor via navegador e PWA;
  • A API de comunicação;
  • A Área administrativa Baltimore.

Cada usuário tem acesso a plataforma através de um serial que é gerado quando o usuário compra o livro físico da Baltimore Education, ou se por qualquer motivo, a Baltimore Education fornecer o acesso a ele (também através de um serial).

O serial tem validade de um ano, e após esse período o usuário precisa cadastrar um novo serial para continuar usando a plataforma. Todo o processo de cobrança ou pagamento para recebimento desses seriais, são todos feitos de maneira externa a plataforma, pela própria Baltimore.

 

3 - 03. Tecnologia e necessidade de atualização

A plataforma foi desenvolvida em 2019/2020 e por tanto, tem padrões de linguagem que a depender do momento em que estiver vendo esse documento, pode estar defasada ou desuatalizada em relação ao que temos de mais moderno para esse tipo de aplicação. Mas temos que ter em mente, as circunstâncias da época e a realidade do cliente no momento do desenvolvimento.

API e Área administrativa:

Desenvolvida em PHP 5.6 puro, com compatibilidade com PHP até a versão 7.4

Área do Aluno/Professor:

HTML5, JavaScript ECMA6 (padrão 2019) e JQuery

 

4 - 04. Comunicação entre API REST e Área do Aluno/Professor

Toda a comunicação entre a Área do Aluno/Professor e o backend é feita através da API REST da plataforma. O core da aplicação pode ser encontrado em js/scripts.js e todos os endpoints podem ser consultados dentro do diretório da API.

No exemplo abaixo uma demonstração da tela de "Suporte e Ajuda" onde após a captura dos dados, a mensagem é disparada para os setores responsáveis. Todas as chamadas dentro da plataforma ocorrem de forma semelhante:

// FUNÇÃO PARA PROCESSAR GET HELP
function procHelp(){
$("#btnGetHelp").html("PROCESSANDO...");
console.log("INICIANDO FUNÇÃO PARA ATUALIZAR DADOS 'GET HELP'");
var idUsuario = localStorage.getItem("idUsuario");
// RECUPERAR DADOS DO FORMULÁRIO GET HELP
var helpName = $("#helpName").val();
var helpEmail = $("#helpEmail").val();
var helpAssunto = $("#helpAssunto").val();
var helpDepartamento = $("#helpDepartamento").val();
var helpDescricao = $("#helpDescricao").val();
if(helpName!="" && helpEmail!="" && helpAssunto!="" && helpDepartamento!="" && helpDescricao!=""){
// INICIO CHAMADA AJAX
var request = $.ajax({
method: "POST",
url: urlApi+"get-help.php",
data:{idUsuario:idUsuario,helpName:helpName,helpEmail:helpEmail,helpAssunto:helpAssunto,helpDepartamento:helpDepartamento,helpDescricao:helpDescricao}
})
request.done(function (dados) {
if (dados["sucesso"]=="200") {
$("#btnGetHelp").html("Send");
mensagem("Mensagem enviada com sucesso! Em breve retornaremos o seu contato.");
}else{
console.log("PROBLEMAS NO ENVIO DA MENSAGEM (procHelp)");
console.log(dados);
// LIMPANDO OS CAMPOS DE LOGIN E SENHA
mensagem("Não conseguimos comunicação com o servidor, tente novamente dentro de alguns instantes.");
}
});
request.fail(function (dados) {
console.log("PROBLEMAS NO ENVIO DA MENSAGEM (procHelp)");
mensagem("Não conseguimos comunicação com o servidor, tente novamente dentro de alguns instantes.");
});
// FINAL CHAMADA AJAX
}else{
mensagem("Todos os campos são necessários");
}
console.log("FUNÇÃO PARA ATUALIZAR DADOS 'GET HELP' FINALIZADA COM SUCESSO'");
}
view raw get-help.js hosted with ❤ by GitHub

Os dados são recebidos pela API que processa as informações e realiza os procedimentos necessários:

<?php
// PERMITIR O ACESSO DE QUALQUER ORIGEM
//header('Access-Control-Allow-Origin: https://127.0.0.1');
header('Access-Control-Allow-Origin: https://www.baltimoreeducation.com.br');
header('Access-Control-Allow-Methods: GET, POST, PUT');
#define o encoding do cabeçalho para utf-8
header('Content-Type: application/json');
// CONEXÃO COM O BANCO DE DADOS
require("conexao.php");
// FUNÇÕES BÁSICAS
require("funcoes.php");
$idUsuario = $_POST["idUsuario"];
$helpName = $_POST["helpName"];
$helpEmail = $_POST["helpEmail"];
$helpAssunto = $_POST["helpAssunto"];
$helpDepartamento = $_POST["helpDepartamento"];
$helpDescricao = $_POST["helpDescricao"];
// RECUPERAR DADOS DO USUÁRIO
$sql = "SELECT * FROM usuarios WHERE id = '$idUsuario'";
$result = $PDO->query( $sql );
$usuario = $result->fetchAll( PDO::FETCH_ASSOC );
$id = $usuario[0]["id"];
$email = $usuario[0]["email"];
$html = "";
$html = $html."<br><b>Usuário:</b> #".$id;
$html = $html."<br><b>E-mail cadastro:</b> ".$email;
$html = $html."<br><b>Nome:</b> ".$helpName;
$html = $html."<br><b>E-mail informado:</b> ".$helpEmail;
$html = $html."<br><b>Assunto:</b> ".$helpAssunto;
$html = $html."<br><b>Departamento:</b> ".$helpDepartamento;
$html = $html."<br><b>Descrição:</b> ".$helpDescricao;
$html = $html."<br><br>Esses dados vieram do formulário de contato KidsRock";
//contato@altidiomas.com
enviarEmail("atendimento@baltimoreeducation.com.br","Solicitação de Suporte KidsRock: ".$helpAssunto,"O usuário ".$helpName." solicitou suporte e esses foram os dados:<br>".$html);
$data = array('sucesso' => "200");
$json_string = json_encode($data, JSON_PRETTY_PRINT);
echo $json_string;
view raw get-help.php hosted with ❤ by GitHub

 

5 - 05. Obtenção de conteúdo e reaproveitamento de memória

Como o conteúdo é relativamente extenso, incluindo diversas imagens, textos, arquivos de aúdios etc. Realizamos o download de todo o material uma única vez, o salvamos na memória, e ai reaproveitamos o mesmo sempre que for necessário para economizar recursos e permitir inclusive que a plataforma continue funcionando mesmo sem conexão com a internet (uma vez que os arquivos já tenham sido baixados):

// FUNÇÃO PARA CARREGAR CONTEÚDO
var conteudo;
var paginas;
function carregarConteudo(){
console.log("INICIANDO FUNÇÃO PARA CARREGAR TODO DO CONTEÚDO");
// INICIO CHAMADA AJAX
var request = $.ajax({
method: "POST",
url: urlApi+"carregar-conteudo.php"
})
request.done(function (dados) {
console.log("%c CONTEÚDO BAIXADO:","background:#ff0000;color:#fff;font-size:20px;");
//console.log(dados);
//console.log("HORA+MINUTOS+5: "+ horaAtualMinutos());
//console.log("TIMESTAMP ATUAL +1 MIN:");
//horaAtualMinutos("01");
conteudo = dados;
console.log(conteudo);
//console.table(conteudo.livros);
//console.table(conteudo.unidades);
//console.table(conteudo.paginas);
// ALIMENTAR DADOS GAMEFICAÇÃO
console.log("%c ALIMENTANDO DADOS GAMEFICAÇÃO:","background:#AD1457;color:#fff;font-size:20px;");
$(".progress-bar").html("<small>"+localStorage.getItem("pontosUsuario")+" pontos</small>");
var nivel = 0;
if(localStorage.getItem("pontosUsuario")>0){
nivel = localStorage.getItem("pontosUsuario") / 10;
nivel = parseInt(nivel);
$("#nivelAtualUsuario").html(nivel);
$("#nivelAtualUsuarioMobile").html(nivel);
}
// VERIFICAR SE EXISTEM REDIRECTS SALVOS PARA SEREM FEITOS
var needRedirect = localStorage.getItem("resetWindow");
if(needRedirect=="sim"){
var resetWindowView = localStorage.getItem("resetWindowView");
//$JSView.goToView('viewComunidade');
loadComunidade();
mensagem("Dados salvos com sucesso!");
// RESETAR A MEMÓRIA RESPONSAVEL PELOS REDIRECTS
localStorage.setItem("resetWindow","nao");
}
});
request.fail(function (dados) {
console.log("PROBLEMAS AO BAIXAR CONTEÚDO (carregarConteudo)");
mensagem("Não conseguimos comunicação com o servidor, tente novamente dentro de alguns instantes.");
});
// FINAL CHAMADA AJAX
}

Na API o processo é semelhante, já realizando todas as querys de uma única vez na autenticação do usuário:

<?php
// PERMITIR O ACESSO DE QUALQUER ORIGEM
//header('Access-Control-Allow-Origin: https://127.0.0.1');
header('Access-Control-Allow-Origin: https://www.baltimoreeducation.com.br');
header('Access-Control-Allow-Methods: GET, POST, PUT');
#define o encoding do cabeçalho para utf-8
header('Content-Type: application/json');
// CONEXÃO COM O BANCO DE DADOS
require("conexao.php");
// FUNÇÕES BÁSICAS
require("funcoes.php");
// OBTER LIVROS
$sql = "SELECT * FROM livros ORDER BY id ASC";
$result = $PDO->query( $sql );
$livros = $result->fetchAll( PDO::FETCH_ASSOC );
$tot_livros = count($livros);
// OBTER UNIDADES
$sql = "SELECT * FROM unidades ORDER BY id_livro, nome ASC";
$result = $PDO->query( $sql );
$unidades = $result->fetchAll( PDO::FETCH_ASSOC );
$tot_unidades = count($unidades);
// OBTER PÁGINAS
$sql = "SELECT * FROM paginas ORDER BY id_livro, ordem, id ASC";
$result = $PDO->query( $sql );
$paginas = $result->fetchAll( PDO::FETCH_ASSOC );
$tot_paginas = count($paginas);
$data = array('sucesso' => "200",
'livros' => $livros,
'tot_livros' => $tot_livros,
'unidades' => $unidades,
'tot_unidades' => $tot_unidades,
'paginas' => $paginas,
'tot_paginas' => $tot_paginas);
$json_string = json_encode($data, JSON_PRETTY_PRINT);
echo $json_string;
?>

Um exemplo desse reaproveitamento de conteúdo, quando o aluno acesso um livro, apenas acessamos o mesmo da memória:

// CARREGAR OS LIVROS
function loadBooks(){
$('#sound1').get(0).pause();
$('#sound2').get(0).play();
desligarAllMusicas();
// FECHAR AUDIO PLAYER
fecharPlayerAudioLivros();
$(".pagina-01 .container.tada").hide();
$(".pagina-01 .container.caixa-conteudo").fadeIn("1900000");
$(".pagina-01 .caixa-conteudo").css("min-height","800px");
// ATIVAR O MENU LIVROS
$(".menu-pai").removeClass("menu-ativo");
$("#menuBooks").addClass("menu-ativo");
$("#menuBooksMobile").addClass("menu-ativo");
$JSView.goToView('viewBooks');
verificarSeriaisAcesso();
var i = 0;
// SB (VAMOS IMPRIMIR O S NA FRENTE DO CÓDIGO DO LIVRO)
console.log("INICIANDO A IMPRESSÃO DOS LIVROS (PRIMEIRA LINHA)");
for(i=0;i<conteudo.tot_livros;i++){
if(conteudo.livros[i]["id"]!="1"){
$("#listLivros").append(`
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-6 livro SBKR${conteudo.livros[i]["cod_livro"]}">
<a href="javascript:void()" title="${conteudo.livros[i]["nome"]}">
${conteudo.livros[i]["nome"]} STUDENT'S BOOK
</a>
<div class="caixa-livro" style="background:url(${urlCnd+conteudo.livros[i]["capa"].replace(" - ","%20-%20")}) no-repeat;background-size:cover;background-position:center center;">
<div class="bloqueio-livro" onclick="procAddSerial();">&nbsp;</div> <a href="javascript:void()" title="${conteudo.livros[i]["nome"]}" onclick="$JSView.goToView(\'viewBooksUnits\'); nomeLivro( \`${conteudo.livros[i]["nome"]} STUDENT'S BOOK\`); loadUnidadesLivro(${conteudo.livros[i]["id"]},\'SB\',\'${conteudo.livros[i]["cod_livro"]}\');"> &nbsp; </a>
</div></div>`);
}
}
// AB (VAMOS IMPRIMIR O A NA FRENTE DO CÓDIGO DO LIVRO)
console.log("INICIANDO A IMPRESSÃO DOS LIVROS (SEGUNDA LINHA)");
for(i=0;i<conteudo.tot_livros;i++){
if(conteudo.livros[i]["id"]!="1"){
$("#listLivros").append('<div class="col-lg-3 col-md-3 col-sm-6 col-xs-6 livro teste-d ABKR'+conteudo.livros[i]["cod_livro"]+'"><a href="javascript:void()" title="'+conteudo.livros[i]["nome"]+'" > '+conteudo.livros[i]["nome"]+' WORKBOOK</a><div class="caixa-livro" style="background:url('+urlCnd+conteudo.livros[i]["capa_ab"].replace(" - ","%20-%20")+') no-repeat;background-size:cover;background-position:center center;"> <div class="bloqueio-livro" onclick="procAddSerial();">&nbsp;</div> <a href="javascript:void()" title="'+conteudo.livros[i]["nome"]+'" onclick="$JSView.goToView(\'viewBooksUnits\'); nomeLivro(\''+conteudo.livros[i]["nome"]+' WORKBOOK\'); loadUnidadesLivro('+conteudo.livros[i]["id"]+',\'AB\',\''+conteudo.livros[i]["cod_livro"]+'\');"> &nbsp; </a></div></div>');
}
}
console.log("SERIAIS ATIVOS DO USUÁRIO");
console.log(listaSeriais);
}
view raw loadbook.js hosted with ❤ by GitHub

 

6 - 06. Games

Cada um dos games tem sua própria mecânica e regras, porém existe uma semelhança entre todos eles: sempre uma função que as monta, as processa (resultado) e as finalizada (contabilizando pontos, avançando níveis etc):

Por exemplo, se analisarmos o Memory Game (jogo da memória):

View:

<jsv-content>
<!-- PAGE CONTENT FIM -->
<div class="page-content">
<div class="titulo-view">
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-3 data-arrow">
<a href="javascript:void(0)" onclick="$JSView.goToView('viewGames'); desligarAllMusicas();">
<img src="images/down-arrow.png" alt="Voltar">
</a>
</div>
<div class="col-lg-8 col-md-8 col-sm-6 col-xs-6 text-center">
<h1 class="mobile-ajuste-margin">Memory Game</h1>
</div>
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-3">&nbsp;</div>
<br clear="both" />
</div>
<br clear="both" />
<!-- AREA DE EDIÇÃO -->
<div class="memory-game">
<div class="col-lg-10 col-md-10 col-lg-offset-1 col-md-offset-1 col-sm-12 col-xs-12 text-center">
<div class="bloquear-memory-game"></div>
<div class="game"></div>
</div>
</div>
<!-- AREA DE EDIÇÃO -->
<br clear="both">
<br clear="both">
<br clear="both">
<br clear="both">
<br clear="both">
</div>
<!-- PAGE CONTENT FIM -->
</jsv-content>

Funções JS:

// AUMENTAR PONTOS PARA GAMEFICAÇÃO
function gameficacao(){
var idUsuario = localStorage.getItem("idUsuario");
// INICIO CHAMADA AJAX
var request = $.ajax({
method: "POST",
url: urlApi+"gameficacao.php",
data:{idUsuario:idUsuario}
})
request.done(function (dados) {
// ALIMENTAR DADOS GAMEFICAÇÃO
console.log("%c ALIMENTANDO DADOS GAMEFICAÇÃO:","background:#AD1457;color:#fff;font-size:20px;");
$(".progress-bar").html("<small>"+dados.pontos+" pontos</small>");
var nivel = 0;
if(dados.pontos>0){
nivel = dados.pontos / 10;
nivel = parseInt(nivel);
$("#nivelAtualUsuario").html(nivel);
$("#nivelAtualUsuarioMobile").html(nivel);
}
mensagem("<i class=\"fa fa-trophy fa-2x diogenes-pulse\" aria-hidden=\"true\" style=\"color: #FDD835;\"></i><br>Você ganhou 1 ponto por ter vencido o desafio do game!");
localStorage.setItem("pontosUsuario",dados.pontos);
});
request.fail(function (dados) {
console.log("PROBLEMAS AO AUMENTAR PONTOS USUÁRIO GAMEFICAÇÃO (gameficacao)");
});
// FINAL CHAMADA AJAX
clearInterval(mkStart);
$("#cronometro").fadeOut("500");
}
view raw gamificacao.js hosted with ❤ by GitHub
function loadMemoryGame(){
$('#sound1').get(0).pause();
//$('#sound2').get(0).play();
desligarAllMusicas();
playMusicBackground("#sound5");
$('#sound5').prop("volume", 0.12); // DIMINUIR O AUDIO DA MÚSICA DE FUNDO DO MEMOERY GAME
$(".pagina-01 .container.tada").hide();
$(".pagina-01 .container.caixa-conteudo").fadeIn("1900000");
$JSView.goToView('viewMemoryGame');
memoryGame();
// ATIVAR O MENU GAMES (ESTA REDUNDANTE)
$(".menu-pai").removeClass("menu-ativo");
$("#menuGames").addClass("menu-ativo");
}
var nomeCarta = [];
var imgCarta = [];
var idCarta = [];
var audioCarta = [];
function memoryGame(){
console.log("%c STORE CRONOMETRO:","background:#fff000;color:#000;");
horaAtualMinutos("memoryGame");
// Memory Game
// © 2014 Nate Wiley
// License -- MIT
// best in full screen, works on phones/tablets (min height for game is 500px..) enjoy ;)
// Follow me on Codepen
(function(){
var Memory = {
init: function(cards){
this.$game = $(".game");
this.$modal = $(".modal");
this.$overlay = $(".modal-overlay");
this.$restartButton = $("button.restart");
this.cardsArray = $.merge(cards, cards);
this.shuffleCards(this.cardsArray);
this.setup();
},
shuffleCards: function(cardsArray){
this.$cards = $(this.shuffle(this.cardsArray));
},
setup: function(){
this.html = this.buildHTML();
this.$game.html(this.html);
this.$memoryCards = $(".card");
this.paused = false;
this.guess = null;
this.binding();
},
binding: function(){
this.$memoryCards.on("click", this.cardClicked);
this.$restartButton.on("click", $.proxy(this.reset, this));
},
// kinda messy but hey
cardClicked: function(){
var _ = Memory;
var $card = $(this);
if(!_.paused && !$card.find(".inside").hasClass("matched") && !$card.find(".inside").hasClass("picked")){
$card.find(".inside").addClass("picked");
if(!_.guess){
_.guess = $(this).attr("data-id");
} else if(_.guess == $(this).attr("data-id") && !$(this).hasClass("picked")){
$(".picked").addClass("matched");
setTimeout(function(){
// DESATIVAMOS O AUDIO DO ACERTO
//playMusic("sounds/goodjob.mp3"); // USUÁRIO ACERTOU
}, 550);
_.guess = null;
} else {
_.guess = null;
_.paused = true;
setTimeout(function(){
$(".picked").removeClass("picked");
// DESATIVAMOS O AUDIO DO ERRO
//playMusic("sounds/try_again.mp3"); // USUARIO ERROU
Memory.paused = false;
}, 550);
}
if($(".matched").length == $(".card").length){
_.win();
}
}
},
win: function(){ // USUAIRIO VENCEU
this.paused = true;
setTimeout(function(){
pauseMusic("#sound5");
playMusicBackground("#sound6");
playMusicBackground("#sound7");
$(".game-vitoria-game").fadeIn("50");
gameficacao();
Memory.showModal();
//Memory.$game.fadeOut();
}, 1000);
},
showModal: function(){
this.$overlay.show();
this.$modal.fadeIn("slow");
},
hideModal: function(){
this.$overlay.hide();
this.$modal.hide();
},
reset: function(){
this.hideModal();
this.shuffleCards(this.cardsArray);
this.setup();
this.$game.show("slow");
pauseMusic("#sound5");
},
// Fisher--Yates Algorithm -- https://bost.ocks.org/mike/shuffle/
shuffle: function(array){
var counter = array.length, temp, index;
// While there are elements in the array
while (counter > 0) {
// Pick a random index
index = Math.floor(Math.random() * counter);
// Decrease counter by 1
counter--;
// And swap the last element with it
temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
},
buildHTML: function(){
var frag = '';
this.$cards.each(function(k, v){
frag += '<div class="card" data-id="'+ v.id +'"><div class="inside">\
<div class="front"><img src="'+ v.img +'"\
alt="'+ v.name +'" /></div>\
<div class="back"><img src="images/costas.svg"\
alt="MagicTree" /></div></div>\
</div>';
});
return frag;
}
};
// CARREGAR AS CARTAS DO MEMORY GAME
var controleCartas = 0;
var controleIndex = 0;
for(var i = 0;i<conteudoGames.length;i++){
if(conteudoGames[i]["tipo"]=="memory_game" && conteudoGames[i]["id_unidade"] == primeiraUnidade){
nomeCarta[controleIndex] = "carta"+controleIndex;
imgCarta[controleIndex] = urlCnd+conteudoGames[i]["link"];
audioCarta[controleIndex] = urlCnd+conteudoGames[i]["audio"];
idCarta[controleIndex] = controleIndex;
controleIndex++;
controleCartas++;
}
}
// FINAL DO FOR
console.log("TOTAL LENGHT MEMORY GAME: "+controleCartas);
if(controleCartas<=4){
var cards = [
{
name: nomeCarta[0],
img: imgCarta[0],
id: idCarta[0]
},
{
name: nomeCarta[1],
img: imgCarta[1],
id: idCarta[1]
},
{
name: nomeCarta[2],
img: imgCarta[2],
id: idCarta[2]
},
{
name: nomeCarta[3],
img: imgCarta[3],
id: idCarta[3]
}
];
}
if(controleCartas==6){
var cards = [
{
name: nomeCarta[0],
img: imgCarta[0],
id: idCarta[0]
},
{
name: nomeCarta[1],
img: imgCarta[1],
id: idCarta[1]
},
{
name: nomeCarta[2],
img: imgCarta[2],
id: idCarta[2]
},
{
name: nomeCarta[3],
img: imgCarta[3],
id: idCarta[3]
},
{
name: nomeCarta[4],
img: imgCarta[4],
id: idCarta[4]
},
{
name: nomeCarta[5],
img: imgCarta[5],
id: idCarta[5]
}
];
}
if(controleCartas==7){
var cards = [
{
name: nomeCarta[0],
img: imgCarta[0],
id: idCarta[0]
},
{
name: nomeCarta[1],
img: imgCarta[1],
id: idCarta[1]
},
{
name: nomeCarta[2],
img: imgCarta[2],
id: idCarta[2]
},
{
name: nomeCarta[3],
img: imgCarta[3],
id: idCarta[3]
},
{
name: nomeCarta[4],
img: imgCarta[4],
id: idCarta[4]
},
{
name: nomeCarta[5],
img: imgCarta[5],
id: idCarta[5]
},
{
name: nomeCarta[6],
img: imgCarta[6],
id: idCarta[6]
}
];
}
if(controleCartas==8){
var cards = [
{
name: nomeCarta[0],
img: imgCarta[0],
id: idCarta[0]
},
{
name: nomeCarta[1],
img: imgCarta[1],
id: idCarta[1]
},
{
name: nomeCarta[2],
img: imgCarta[2],
id: idCarta[2]
},
{
name: nomeCarta[3],
img: imgCarta[3],
id: idCarta[3]
},
{
name: nomeCarta[4],
img: imgCarta[4],
id: idCarta[4]
},
{
name: nomeCarta[5],
img: imgCarta[5],
id: idCarta[5]
},
{
name: nomeCarta[6],
img: imgCarta[6],
id: idCarta[6]
},
{
name: nomeCarta[7],
img: imgCarta[7],
id: idCarta[7]
}
];
}
//console.log("O QUE EU SOU");
//console.log(cards);
Memory.init(cards);
})();
}
// AO CLICAR EM UMA CARTA DO MEMORY GAME, VAMOS TOCAR O SOM CORRESPONDENTE
$('body').on('click', 'div.card', function() {
var urlMusica = $(this).attr("data-id");
console.log("CARTA CLICADA FOI A: "+urlMusica);
// E AI DE ACORDO COM A MÚSICA TOCAMOS O SOM
if(urlMusica==0){
//$("#sound8").attr("src",audioCarta[0]);
playMusic(audioCarta[0]);
}
if(urlMusica==1){
//$("#sound9").attr("src",audioCarta[1]);
playMusic(audioCarta[1]);
}
if(urlMusica==2){
//$("#sound10").attr("src",audioCarta[2]);
playMusic(audioCarta[2]);
}
if(urlMusica==3){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[3]);
}
if(urlMusica==4){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[4]);
}
if(urlMusica==5){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[5]);
}
if(urlMusica==6){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[6]);
}
if(urlMusica==7){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[7]);
}
if(urlMusica==8){
//$("#sound11").attr("src",audioCarta[3]);
playMusic(audioCarta[8]);
}
});
view raw memory-game.js hosted with ❤ by GitHub

 

7 - 07. PWA

Como vimos anteriormente, reaproveitamos bastante a memória já salva, o que facilita para a execução do PWA, que está presente no diretório "/instalador". Criamos o service worker e pronto:

function installApp() {
// Show the prompt
deferredPrompt.prompt();
setupButton.disabled = true;
// Wait for the user to respond to the prompt
deferredPrompt.userChoice
.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('PWA setup accepted');
// hide our user interface that shows our A2HS button
setupButton.style.display = 'none';
$("#naoInstalado").hide(0);
$("#instalado").fadeIn("500");
} else {
console.log('PWA setup rejected');
$("#naoInstalado").hide(0);
$("#instalado").fadeIn("500");
}
deferredPrompt = null;
});
}
view raw install.js hosted with ❤ by GitHub
var cacheName = 'kidsrock';
var cached_urls = [
'/kidsrock/nstalador/',
'/kidsrock/instalador/index.html',
'/kidsrock/instalador/cadastro.html',
'/kidsrock/instalador/esqueci-minha-senha.html',
'/kidsrock/instalador/serial.html',
'/kidsrock/instalador/welcome.html',
'/kidsrock/instalador/welcome-professor.html',
'/kidsrock/instalador/css/style.css',
'/kidsrock/instalador/css/bootstrap.css',
//'/instalador/css/',
//'/instalador/js/',
'/kidsrock/instalador/js/scripts.js',
//'/instalador/images/',
//'/instalador/sounds/',
//'/instalador/arquivos/'
];
/* Start the service worker and cache all of the app's content */
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll(cached_urls);
})
);
});
/* Serve cached content when offline */
self.addEventListener('fetch', function(e) {
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request);
})
);
});
view raw sw.js hosted with ❤ by GitHub

 

8 - 08. Área administrativa (Backend)

Não há muito o que se descrever sobre essa área, a não ser que, todo o acesso ao banco de dados é feito de forma independente, ou seja, a API é usada apenas para a comunicação entre a Área do Aluno/Professor e o banco. A Área administrativa à acessa de forma direta, e todo o fluxo pode ser percebido pela própria organização do diretório.

O mesmo vale para os arquivos de mídia, que são carregados dentro do diretório "/cdn", universalizando o acesso seja pela Área administrativa, seja pela Área do Aluno/Professor.

 

9 - 09. Implementações futuras

Alguns itens seriam interessante serem implementados futuramente em eventuais novas versões da plataforma:

  • Atualização para a versão do PHP 8.0+;
  • Atualização do padrão JavaScript para ECMA6 (2021), removendo e substituíndo todas as chamadas JQuery;
  • Criação da versão 2 da API, para um padrão MVC, assim como a Área administrativa e a API V2 ser o único canal para acesso ao banco de dados.
  • Implementação de tokenização JWT para OAuth dos usuários;

 

10 - 10. Conclusão

Alguns links de apoio sobre o desenvolvimento da plataforma:

Qualquer dúvida deve ser enviada diretamente para contato@mangu.com.br ou para contato@fabricadeplugins.com.br.

 

Precisa de Suporte?

Tem alguma dúvida, ou precisa de Suporte? Clique aqui para abrir um chamado técnico! É só abrir uma conta ou fazer login na nossa Central de Atendimento. Nosso prazo de atendimento para os chamados técnicos são em média de 24 horas úteis (ou três dias corridos, de seg. à sex.). Não sabe como abrir um chamado? Aqui tem um vídeo mostrando como fazer isso.

Posso enviar mensagens no WhatsAapp?

Claro! Mas note que no WhatsApp as respostas podem demorar um pouco mais dependendo do número de mensagens que tivermos recebido, mas se enviou por lá, é só aguardar que assim que possível você terá um retorno.


Getting Started
Product Features
Customization
Help