generated from ricardo/MVCLogin
feat: tela para cadastrar nova postagem
This commit is contained in:
parent
4b04639ad7
commit
955a131fec
BIN
LogoPoost.png
Normal file
BIN
LogoPoost.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 107 KiB |
17
Postall.Domain/Dtos/Responses/FacebookTokenResponse.cs
Normal file
17
Postall.Domain/Dtos/Responses/FacebookTokenResponse.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Models/FacebookTokenResponse.cs
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Postall.Domain.Dtos.Responses
|
||||||
|
{
|
||||||
|
public class FacebookTokenResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("access_token")]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("token_type")]
|
||||||
|
public string TokenType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("expires_in")]
|
||||||
|
public long ExpiresIn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Postall.Domain/Entities/FacebookToken.cs
Normal file
14
Postall.Domain/Entities/FacebookToken.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Postall.Domain.Entities
|
||||||
|
{
|
||||||
|
public class FacebookToken
|
||||||
|
{
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
public DateTime ExpiresAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Postall.Domain/Entities/UserSocialData.cs
Normal file
20
Postall.Domain/Entities/UserSocialData.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace Postall.Domain.Entities
|
||||||
|
{
|
||||||
|
public class UserSocialData
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
public ObjectId Id { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
public string GoogleToken { get; set; }
|
||||||
|
public FacebookToken FacebookToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MongoDB.Bson" Version="3.1.0" />
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="3.1.0" />
|
||||||
<PackageReference Include="Serilog" Version="4.0.2" />
|
<PackageReference Include="Serilog" Version="4.0.2" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
||||||
@ -15,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\vcart.me\vcart.back\Struct.ValueObjects\BaseDomain.csproj" />
|
<ProjectReference Include="..\BaseDomain\BaseDomain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
14
Postall.Domain/Services/IFacebookServices.cs
Normal file
14
Postall.Domain/Services/IFacebookServices.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Postall.Domain.Services
|
||||||
|
{
|
||||||
|
public interface IFacebookServices
|
||||||
|
{
|
||||||
|
Task<string> GetLongLivedToken(string shortLivedToken);
|
||||||
|
Task SaveFacebookToken(string userId, string token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,8 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MongoDB.Bson" Version="2.28.0" />
|
<PackageReference Include="MongoDB.Bson" Version="3.1.0" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="2.28.0" />
|
<PackageReference Include="MongoDB.Driver" Version="3.1.0" />
|
||||||
<PackageReference Include="Serilog" Version="4.0.2" />
|
<PackageReference Include="Serilog" Version="4.0.2" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
||||||
@ -16,4 +16,8 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.0" />
|
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Postall.Domain\Postall.Domain.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
49
Postall.Infra/Services/FacebookTokenService.cs
Normal file
49
Postall.Infra/Services/FacebookTokenService.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using Postall.Domain.Dtos.Responses;
|
||||||
|
using Postall.Domain.Entities;
|
||||||
|
using Postall.Domain.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Postall.Infra.Services
|
||||||
|
{
|
||||||
|
public class FacebookTokenService: IFacebookServices
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<UserSocialData> _tokens;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public async Task<string> GetLongLivedToken(string shortLivedToken)
|
||||||
|
{
|
||||||
|
var appId = _config["Authentication:Facebook:AppId"];
|
||||||
|
var appSecret = _config["Authentication:Facebook:AppSecret"];
|
||||||
|
|
||||||
|
var response = await _httpClient.GetFromJsonAsync<FacebookTokenResponse>(
|
||||||
|
$"https://graph.facebook.com/oauth/access_token?" +
|
||||||
|
$"grant_type=fb_exchange_token&" +
|
||||||
|
$"client_id={appId}&" +
|
||||||
|
$"client_secret={appSecret}&" +
|
||||||
|
$"fb_exchange_token={shortLivedToken}");
|
||||||
|
|
||||||
|
return response.AccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveFacebookToken(string userId, string token)
|
||||||
|
{
|
||||||
|
var update = Builders<UserSocialData>.Update
|
||||||
|
.Set(x => x.FacebookToken.AccessToken, token)
|
||||||
|
.Set(x => x.FacebookToken.ExpiresAt, DateTime.UtcNow.AddDays(60));
|
||||||
|
|
||||||
|
await _tokens.UpdateOneAsync(
|
||||||
|
x => x.UserId == userId,
|
||||||
|
update,
|
||||||
|
new UpdateOptions { IsUpsert = true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,11 +2,19 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Facebook;
|
using Microsoft.AspNetCore.Authentication.Facebook;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Postall.Domain.Services;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace Postall.Controllers
|
namespace Postall.Controllers
|
||||||
{
|
{
|
||||||
public class OtherLoginsController : Controller
|
public class OtherLoginsController : Controller
|
||||||
{
|
{
|
||||||
|
private readonly IFacebookServices _facebookServices;
|
||||||
|
|
||||||
|
public OtherLoginsController(IFacebookServices facebookServices)
|
||||||
|
{
|
||||||
|
this._facebookServices = facebookServices;
|
||||||
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
{
|
{
|
||||||
@ -24,21 +32,13 @@ namespace Postall.Controllers
|
|||||||
public async Task<IActionResult> FacebookResponse()
|
public async Task<IActionResult> FacebookResponse()
|
||||||
{
|
{
|
||||||
var result = await HttpContext.AuthenticateAsync(FacebookDefaults.AuthenticationScheme);
|
var result = await HttpContext.AuthenticateAsync(FacebookDefaults.AuthenticationScheme);
|
||||||
|
if (!result.Succeeded) return RedirectToAction("Login");
|
||||||
|
|
||||||
if (!result.Succeeded)
|
var accessToken = result.Properties.GetTokenValue("access_token");
|
||||||
return RedirectToAction("Login");
|
var longLivedToken = await _facebookServices.GetLongLivedToken(accessToken);
|
||||||
|
|
||||||
var claims = result.Principal.Identities.FirstOrDefault()
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
.Claims.Select(claim => new
|
await _facebookServices.SaveFacebookToken(userId, longLivedToken);
|
||||||
{
|
|
||||||
claim.Issuer,
|
|
||||||
claim.OriginalIssuer,
|
|
||||||
claim.Type,
|
|
||||||
claim.Value
|
|
||||||
});
|
|
||||||
|
|
||||||
// Aqui você pode implementar sua lógica de login
|
|
||||||
// Por exemplo, criar ou atualizar o usuário no banco de dados
|
|
||||||
|
|
||||||
return RedirectToAction("Index", "Home");
|
return RedirectToAction("Index", "Home");
|
||||||
}
|
}
|
||||||
|
|||||||
91
Postall/Controllers/SocialMediaController.cs
Normal file
91
Postall/Controllers/SocialMediaController.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Postall.Models;
|
||||||
|
|
||||||
|
namespace Postall.Controllers
|
||||||
|
{
|
||||||
|
public class SocialMediaController : Controller
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
// Implementar lógica para buscar lista de posts
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public JsonResult GetPostDetails(int postId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Implementar lógica para buscar detalhes do post
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public JsonResult GetSocialMediaStatus(int postId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Implementar lógica para buscar status das redes sociais
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Post()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public JsonResult SaveDraft([FromBody] PostViewModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Lógica para salvar rascunho
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public JsonResult PublishPost([FromBody] PostViewModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Lógica para publicar post
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public JsonResult SchedulePost([FromBody] PostScheduleViewModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Lógica para agendar post
|
||||||
|
return Json(new { success = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Postall/Models/PostListViewModel.cs
Normal file
12
Postall/Models/PostListViewModel.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Postall.Models
|
||||||
|
{
|
||||||
|
public class PostListViewModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Channel { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime? NextScheduledDate { get; set; }
|
||||||
|
public DateTime LastUpdate { get; set; }
|
||||||
|
public List<SocialMediaStatusViewModel> SocialMediaStatus { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Postall/Models/PostScheduleViewModel.cs
Normal file
9
Postall/Models/PostScheduleViewModel.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Postall.Models
|
||||||
|
{
|
||||||
|
public class PostScheduleViewModel
|
||||||
|
{
|
||||||
|
public bool IsManual { get; set; }
|
||||||
|
public DayOfWeek? WeekDay { get; set; }
|
||||||
|
public TimeSpan? Time { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Postall/Models/PostViewModel.cs
Normal file
10
Postall/Models/PostViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Postall.Models
|
||||||
|
{
|
||||||
|
public class PostViewModel
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public List<string> SelectedPlatforms { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Postall/Models/SocialMediaStatusViewModel.cs
Normal file
9
Postall/Models/SocialMediaStatusViewModel.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Postall.Models
|
||||||
|
{
|
||||||
|
public class SocialMediaStatusViewModel
|
||||||
|
{
|
||||||
|
public string Platform { get; set; }
|
||||||
|
public DateTime? NextScheduledDate { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -32,6 +32,11 @@
|
|||||||
<Folder Include="wwwroot\img\" />
|
<Folder Include="wwwroot\img\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Postall.Domain\Postall.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\Postall.Infra\Postall.Infra.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Resource.Designer.cs">
|
<Compile Update="Resource.Designer.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
|
|||||||
@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Authentication.Google;
|
|||||||
using Microsoft.AspNetCore.Localization;
|
using Microsoft.AspNetCore.Localization;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Postall.Domain.Services;
|
||||||
|
using Postall.Infra.Services;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Sinks.Grafana.Loki;
|
using Serilog.Sinks.Grafana.Loki;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
@ -86,6 +88,8 @@ builder.Services.AddControllersWithViews();
|
|||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
builder.Services.AddSerilog();
|
builder.Services.AddSerilog();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IFacebookServices, FacebookTokenService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
|
var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Site";
|
ViewData["Title"] = "Sites";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<h1 class="display-4">Login</h1>
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center align-items-center min-vh-100">
|
||||||
<div class="col-md-4">
|
<div class="col-md-6">
|
||||||
|
<div class="card shadow-lg">
|
||||||
|
<div class="card-body text-center p-5">
|
||||||
|
<h2 class="card-title mb-4">Bem-vindo</h2>
|
||||||
|
<p class="card-text text-muted mb-4">
|
||||||
|
Faça login com sua conta Microsoft para acessar o chat.
|
||||||
|
</p>
|
||||||
|
|
||||||
<form asp-action="FacebookLogin" method="get">
|
<form asp-action="FacebookLogin" method="get">
|
||||||
<button type="submit" class="btn btn-primary btn-block">
|
<button type="submit" class="btn btn-primary btn-block">
|
||||||
<i class="fab fa-facebook"></i> Login com Facebook
|
<i class="fab fa-facebook"></i> Login com Facebook
|
||||||
@ -13,4 +20,35 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@section Styles {
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #2f2f2f;
|
||||||
|
border: none;
|
||||||
|
padding: 12px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #404040;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||||
|
}
|
||||||
|
|||||||
@ -32,6 +32,15 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-white" asp-area="" asp-controller="Plans" asp-action="Index">Planos</a>
|
<a class="nav-link text-white" asp-area="" asp-controller="Plans" asp-action="Index">Planos</a>
|
||||||
</li>
|
</li>
|
||||||
|
@if (User!=null && User.Identity!=null && User.Identity.IsAuthenticated)
|
||||||
|
{
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-white" asp-area="" asp-controller="OtherLogins" asp-action="Index">Sites</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-white" asp-area="" asp-controller="SocialMedia" asp-action="Index">Postagens</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
@if (User!=null && User.Identity!=null && !User.Identity.IsAuthenticated)
|
@if (User!=null && User.Identity!=null && !User.Identity.IsAuthenticated)
|
||||||
{
|
{
|
||||||
@ -44,11 +53,6 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ul class="navbar-nav ml-auto">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link text-white" asp-area="" asp-controller="OtherLogins" asp-action="Index">Sites</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
<partial name="_Language"/>
|
<partial name="_Language"/>
|
||||||
<li class="nav-item dropdown" style="margin-right: 10px">
|
<li class="nav-item dropdown" style="margin-right: 10px">
|
||||||
|
|||||||
254
Postall/Views/SocialMedia/Index.cshtml
Normal file
254
Postall/Views/SocialMedia/Index.cshtml
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
@using Postall.Models
|
||||||
|
|
||||||
|
<!-- Views/SocialMedia/Index.cshtml -->
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Gerenciador de Postagens";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid mt-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2>Gerenciador de Postagens</h2>
|
||||||
|
<a href="@Url.Action("Post", "SocialMedia")" class="btn btn-primary">
|
||||||
|
<i class="bi bi-plus-circle"></i> Nova Postagem
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover" id="postsTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Canal</th>
|
||||||
|
<th>Título</th>
|
||||||
|
<th>Próxima Data</th>
|
||||||
|
<th>Última Atualização</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Os dados serão preenchidos via JavaScript -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Template para detalhes expandidos -->
|
||||||
|
<template id="detailsTemplate">
|
||||||
|
<div class="expanded-details p-3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h5 class="mb-3">Status das Redes Sociais</h5>
|
||||||
|
<div class="social-media-grid">
|
||||||
|
<!-- Facebook -->
|
||||||
|
<div class="social-media-item">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="bi bi-facebook me-2"></i>
|
||||||
|
<span class="platform-name">Facebook</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-badge">
|
||||||
|
<span class="badge rounded-pill status-placeholder">Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="next-date small text-muted mt-1">
|
||||||
|
Próxima data: <span class="date-placeholder">--/--/----</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Instagram -->
|
||||||
|
<div class="social-media-item">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="bi bi-instagram me-2"></i>
|
||||||
|
<span class="platform-name">Instagram</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-badge">
|
||||||
|
<span class="badge rounded-pill status-placeholder">Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="next-date small text-muted mt-1">
|
||||||
|
Próxima data: <span class="date-placeholder">--/--/----</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Twitter/X -->
|
||||||
|
<div class="social-media-item">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="bi bi-twitter-x me-2"></i>
|
||||||
|
<span class="platform-name">Twitter/X</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-badge">
|
||||||
|
<span class="badge rounded-pill status-placeholder">Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="next-date small text-muted mt-1">
|
||||||
|
Próxima data: <span class="date-placeholder">--/--/----</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- WhatsApp -->
|
||||||
|
<div class="social-media-item">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="bi bi-whatsapp me-2"></i>
|
||||||
|
<span class="platform-name">WhatsApp</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-badge">
|
||||||
|
<span class="badge rounded-pill status-placeholder">Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="next-date small text-muted mt-1">
|
||||||
|
Próxima data: <span class="date-placeholder">--/--/----</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Telegram -->
|
||||||
|
<div class="social-media-item">
|
||||||
|
<div class="d-flex align-items-center mb-2">
|
||||||
|
<i class="bi bi-telegram me-2"></i>
|
||||||
|
<span class="platform-name">Telegram</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-badge">
|
||||||
|
<span class="badge rounded-pill status-placeholder">Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="next-date small text-muted mt-1">
|
||||||
|
Próxima data: <span class="date-placeholder">--/--/----</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
@section Styles {
|
||||||
|
<style>
|
||||||
|
.social-media-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-media-item {
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge .badge {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.status-publicado { background-color: #198754; }
|
||||||
|
.badge.status-nao-selecionado { background-color: #6c757d; }
|
||||||
|
.badge.status-gerado { background-color: #0dcaf0; }
|
||||||
|
.badge.status-agendado { background-color: #ffc107; color: #000; }
|
||||||
|
.badge.status-automatizado { background-color: #0d6efd; }
|
||||||
|
|
||||||
|
tr.expanded {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded-details {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@media (max-width: 768px) {
|
||||||
|
.social-media-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
loadPosts();
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadPosts() {
|
||||||
|
$.get('@Url.Action("GetPostDetails", "SocialMedia")', function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
renderPosts(data.posts);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPosts(posts) {
|
||||||
|
const tbody = $('#postsTable tbody');
|
||||||
|
tbody.empty();
|
||||||
|
|
||||||
|
posts.forEach(post => {
|
||||||
|
const row = $(`
|
||||||
|
<tr data-post-id="${post.id}">
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-link expand-btn">
|
||||||
|
<i class="bi bi-chevron-right"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td>${post.channel}</td>
|
||||||
|
<td>${post.title}</td>
|
||||||
|
<td>${formatDate(post.nextScheduledDate)}</td>
|
||||||
|
<td>${formatDate(post.lastUpdate)}</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
|
||||||
|
tbody.append(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(dateString) {
|
||||||
|
if (!dateString) return '--/--/----';
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString('pt-BR');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusBadgeClass(status) {
|
||||||
|
const statusMap = {
|
||||||
|
'publicado': 'status-publicado',
|
||||||
|
'não selecionado': 'status-nao-selecionado',
|
||||||
|
'gerado': 'status-gerado',
|
||||||
|
'agendado': 'status-agendado',
|
||||||
|
'automatizado': 'status-automatizado'
|
||||||
|
};
|
||||||
|
return statusMap[status.toLowerCase()] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('click', '.expand-btn', function() {
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
const postId = row.data('post-id');
|
||||||
|
const icon = $(this).find('i');
|
||||||
|
|
||||||
|
if (row.next().hasClass('details-row')) {
|
||||||
|
// Fechar detalhes
|
||||||
|
row.next().remove();
|
||||||
|
row.removeClass('expanded');
|
||||||
|
icon.removeClass('bi-chevron-down').addClass('bi-chevron-right');
|
||||||
|
} else {
|
||||||
|
// Abrir detalhes
|
||||||
|
$.get(`@Url.Action("GetSocialMediaStatus", "SocialMedia")?postId=${postId}`, function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
const template = document.getElementById('detailsTemplate');
|
||||||
|
const detailsContent = template.content.cloneNode(true);
|
||||||
|
|
||||||
|
// Preencher os status
|
||||||
|
data.socialMediaStatus.forEach(status => {
|
||||||
|
const platformElement = $(detailsContent).find(`[data-platform="${status.platform}"]`);
|
||||||
|
platformElement.find('.status-placeholder')
|
||||||
|
.text(status.status)
|
||||||
|
.addClass(getStatusBadgeClass(status.status));
|
||||||
|
platformElement.find('.date-placeholder').text(formatDate(status.nextScheduledDate));
|
||||||
|
});
|
||||||
|
|
||||||
|
const detailsRow = $('<tr class="details-row">').append(
|
||||||
|
$('<td colspan="5">').append(detailsContent)
|
||||||
|
);
|
||||||
|
|
||||||
|
row.addClass('expanded');
|
||||||
|
row.after(detailsRow);
|
||||||
|
icon.removeClass('bi-chevron-right').addClass('bi-chevron-down');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
347
Postall/Views/SocialMedia/Post.cshtml
Normal file
347
Postall/Views/SocialMedia/Post.cshtml
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
@using Postall.Models
|
||||||
|
@model PostViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Gerenciar Postagens";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<!-- Menu lateral em desktop / Menu superior em mobile -->
|
||||||
|
<div class="col-md-3 col-12 mb-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5>Plataformas</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap gap-2">
|
||||||
|
<button type="button" class="btn btn-outline-primary platform-btn" data-platform="facebook">
|
||||||
|
Facebook
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary platform-btn" data-platform="instagram">
|
||||||
|
Instagram
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary platform-btn" data-platform="twitter">
|
||||||
|
Twitter/X
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary platform-btn" data-platform="whatsapp">
|
||||||
|
WhatsApp
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary platform-btn" data-platform="telegram">
|
||||||
|
Telegram
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5>Agendamento</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input class="form-check-input" type="radio" name="schedule" id="manual" checked>
|
||||||
|
<label class="form-check-label" for="manual">Manual</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input class="form-check-input" type="radio" name="schedule" id="weekly">
|
||||||
|
<label class="form-check-label" for="weekly">Semanal</label>
|
||||||
|
</div>
|
||||||
|
<div id="weeklyOptions" class="d-none">
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="1" id="monday">
|
||||||
|
<label class="form-check-label" for="monday">Segunda-feira</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="2" id="tuesday">
|
||||||
|
<label class="form-check-label" for="tuesday">Terça-feira</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="3" id="wednesday">
|
||||||
|
<label class="form-check-label" for="wednesday">Quarta-feira</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="4" id="thursday">
|
||||||
|
<label class="form-check-label" for="thursday">Quinta-feira</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="5" id="friday">
|
||||||
|
<label class="form-check-label" for="friday">Sexta-feira</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="6" id="saturday">
|
||||||
|
<label class="form-check-label" for="saturday">Sábado</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input weekday-check" type="checkbox" value="0" id="sunday">
|
||||||
|
<label class="form-check-label" for="sunday">Domingo</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="time" class="form-control" id="scheduleTime">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Preview lateral -->
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5>Video</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Canal</label>
|
||||||
|
<input type="text" class="form-control" id="previewChannel" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">URL do Vídeo</label>
|
||||||
|
<input type="text" class="form-control" id="previewVideoUrl">
|
||||||
|
</div>
|
||||||
|
<div class="preview-content">
|
||||||
|
<h6>Título</h6>
|
||||||
|
<p id="previewTitle"></p>
|
||||||
|
<h6>Conteúdo</h6>
|
||||||
|
<p id="previewContent"></p>
|
||||||
|
<div id="previewImage" class="mt-2"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="button" class="btn btn-secondary me-2" onclick="savePlatformDraft()">Gerar com IA</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5>Nova Postagem</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="postTitle" class="form-label">Título</label>
|
||||||
|
<input type="text" class="form-control" id="postTitle">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="postContent" class="form-label">Conteúdo</label>
|
||||||
|
<textarea class="form-control" id="postContent" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="postImage" class="form-label">Imagem</label>
|
||||||
|
<input type="file" class="form-control" id="postImage" accept="image/*">
|
||||||
|
</div>
|
||||||
|
<div class="preview-image mb-3 d-none">
|
||||||
|
<img id="imagePreview" src="#" alt="Preview" class="img-fluid">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="button" class="btn btn-secondary me-2" onclick="saveDraft()">Salvar Rascunho</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="publishPost()">Publicar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
let selectedPlatform = null;
|
||||||
|
|
||||||
|
// Gestão das plataformas
|
||||||
|
document.querySelectorAll('.platform-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async function() {
|
||||||
|
const platform = this.dataset.platform;
|
||||||
|
|
||||||
|
// Reset outros botões
|
||||||
|
document.querySelectorAll('.platform-btn').forEach(b =>
|
||||||
|
b.classList.replace('btn-primary', 'btn-outline-primary'));
|
||||||
|
|
||||||
|
// Ativar botão selecionado
|
||||||
|
this.classList.replace('btn-outline-primary', 'btn-primary');
|
||||||
|
selectedPlatform = platform;
|
||||||
|
|
||||||
|
// Carregar dados da plataforma
|
||||||
|
await loadPlatformData(platform);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadPlatformData(platform) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/socialMedia/platformData/${platform}`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Atualizar preview
|
||||||
|
document.getElementById('previewChannel').value = data.channel;
|
||||||
|
document.getElementById('previewVideoUrl').value = data.videoUrl;
|
||||||
|
document.getElementById('previewTitle').textContent = data.title;
|
||||||
|
document.getElementById('previewContent').textContent = data.content;
|
||||||
|
|
||||||
|
if (data.imageUrl) {
|
||||||
|
document.getElementById('previewImage').innerHTML =
|
||||||
|
`<img src="${data.imageUrl}" class="img-fluid" alt="Preview">`;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao carregar dados da plataforma:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar/ocultar opções de agendamento semanal
|
||||||
|
document.getElementById('weekly').addEventListener('change', function() {
|
||||||
|
document.getElementById('weeklyOptions').classList.remove('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('manual').addEventListener('change', function() {
|
||||||
|
document.getElementById('weeklyOptions').classList.add('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Preview da imagem
|
||||||
|
document.getElementById('postImage').addEventListener('change', function(e) {
|
||||||
|
if (e.target.files && e.target.files[0]) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
document.getElementById('imagePreview').src = e.target.result;
|
||||||
|
document.querySelector('.preview-image').classList.remove('d-none');
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(e.target.files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function getSelectedPlatform() {
|
||||||
|
return selectedPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedWeekDays() {
|
||||||
|
return Array.from(document.querySelectorAll('.weekday-check:checked'))
|
||||||
|
.map(checkbox => parseInt(checkbox.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateAIContent() {
|
||||||
|
if (!selectedPlatform) {
|
||||||
|
alert('Selecione uma plataforma primeiro!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/socialMedia/generateContent', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
platform: selectedPlatform,
|
||||||
|
videoUrl: document.getElementById('previewVideoUrl').value
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.success) {
|
||||||
|
document.getElementById('previewTitle').textContent = data.title;
|
||||||
|
document.getElementById('previewContent').textContent = data.content;
|
||||||
|
} else {
|
||||||
|
alert('Erro ao gerar conteúdo: ' + data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao gerar conteúdo:', error);
|
||||||
|
alert('Erro ao gerar conteúdo');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function savePlatformDraft() {
|
||||||
|
if (!selectedPlatform) {
|
||||||
|
alert('Selecione uma plataforma primeiro!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
platform: selectedPlatform,
|
||||||
|
title: document.getElementById('previewTitle').textContent,
|
||||||
|
content: document.getElementById('previewContent').textContent,
|
||||||
|
videoUrl: document.getElementById('previewVideoUrl').value
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/socialMedia/savePlatformDraft', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
alert('Rascunho salvo com sucesso!');
|
||||||
|
} else {
|
||||||
|
alert('Erro ao salvar rascunho: ' + result.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao salvar rascunho:', error);
|
||||||
|
alert('Erro ao salvar rascunho');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function publishPost() {
|
||||||
|
const isWeekly = document.getElementById('weekly').checked;
|
||||||
|
const data = {
|
||||||
|
title: document.getElementById('postTitle').value,
|
||||||
|
content: document.getElementById('postContent').value,
|
||||||
|
platform: getSelectedPlatform()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isWeekly) {
|
||||||
|
data.isManual = false;
|
||||||
|
data.weekDays = getSelectedWeekDays();
|
||||||
|
data.time = document.getElementById('scheduleTime').value;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '@Url.Action("SchedulePost", "SocialMedia")',
|
||||||
|
type: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
alert('Post agendado com sucesso!');
|
||||||
|
} else {
|
||||||
|
alert('Erro ao agendar post: ' + response.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$.ajax({
|
||||||
|
url: '@Url.Action("PublishPost", "SocialMedia")',
|
||||||
|
type: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
alert('Post publicado com sucesso!');
|
||||||
|
} else {
|
||||||
|
alert('Erro ao publicar post: ' + response.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.platform-btn {
|
||||||
|
min-width: 120px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image img {
|
||||||
|
max-height: 300px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@media (max-width: 768px) {
|
||||||
|
.container-fluid {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -18,8 +18,8 @@
|
|||||||
"AppSecret": "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"
|
"AppSecret": "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"
|
||||||
},
|
},
|
||||||
"Facebook": {
|
"Facebook": {
|
||||||
"AppId": "seu_app_id_aqui",
|
"AppId": "963281005306692",
|
||||||
"AppSecret": "seu_app_secret_aqui"
|
"AppSecret": "575839ccbb36d1457715f1f6dd0a8db9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user