Refactor API structure and update flag handling

- Replaced references to `api.settings` with `api.etichette`, `api.flags`, and `api.strings` in various admin pages to align with new API structure.
- Removed the deprecated `settingsRouter` and introduced `flagsRouter`, `etichetteRouter`, and `stringsRouter` to handle respective functionalities.
- Updated the `Flags` schema to change the `value` field from string to boolean.
- Modified flag handling logic in the `SendMessage` and `NewMail` functions to check for boolean flags instead of string values.
- Added migration script to convert the `value` column in the `flags` table from string to boolean.
- Implemented new routers for banners, etichette, flags, revalidation, and strings to encapsulate related functionalities.
This commit is contained in:
Marco Pedone 2025-11-20 12:38:42 +01:00
parent 3ea9354abb
commit 9c18ca37ab
27 changed files with 555 additions and 495 deletions

View file

@ -0,0 +1,25 @@
-- Converts the 'value' column from a string to a boolean.
-- If 'value' is 'true' (case insensitive), it will be set to TRUE, otherwise FALSE.
DO $$
BEGIN
-- Check if the column is not already boolean
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'flags'
AND column_name = 'value'
AND data_type != 'boolean'
) THEN
-- Convert the column type
ALTER TABLE public.flags
ALTER COLUMN value TYPE BOOLEAN USING (LOWER(value) = 'true');
END IF;
END $$;
-- Ensure that the 'value' column is not NULL (idempotent)
ALTER TABLE public.flags ALTER COLUMN VALUE SET NOT NULL;
-- Set a default value for the 'value' column (idempotent)
ALTER TABLE public.flags ALTER COLUMN VALUE SET DEFAULT FALSE;

View file

@ -51,7 +51,7 @@ export const Layout = ({
containerClassName, containerClassName,
footerClassName, footerClassName,
}: Props) => { }: Props) => {
const { data: bannerData } = api.settings.getBannerData.useQuery({ const { data: bannerData } = api.banners.getBannerData.useQuery({
area_riservata: false, area_riservata: false,
}); });
@ -87,7 +87,7 @@ export const AreaRiservataLayout = ({
containerClassName, containerClassName,
footerClassName, footerClassName,
}: AreaRiservataLayoutProps) => { }: AreaRiservataLayoutProps) => {
const { data: bannerData } = api.settings.getBannerData.useQuery({ const { data: bannerData } = api.banners.getBannerData.useQuery({
area_riservata: true, area_riservata: true,
}); });
const session = useSession(); const session = useSession();

View file

@ -77,7 +77,7 @@ export const EtichetteModal = ({
const [selected, setSelected] = useState<EtichetteIdEtichetta | null>(null); const [selected, setSelected] = useState<EtichetteIdEtichetta | null>(null);
const utils = api.useUtils(); const utils = api.useUtils();
const { data } = api.chat.getChatEtichette.useQuery({ chatId }); const { data } = api.chat.getChatEtichette.useQuery({ chatId });
const { data: etichette } = api.settings.getAllEtichette.useQuery(); const { data: etichette } = api.etichette.getAllEtichette.useQuery();
const { mutate: remove } = api.chat.removeEtichettaFromChat.useMutation({ const { mutate: remove } = api.chat.removeEtichettaFromChat.useMutation({
onSuccess: async () => { onSuccess: async () => {

View file

@ -4,12 +4,11 @@ import { DataTable } from "~/components/custom_ui/data-table";
import { DataTableColumnHeader } from "~/components/custom_ui/dataTable-header"; import { DataTableColumnHeader } from "~/components/custom_ui/dataTable-header";
import type { SearchFiltro } from "~/components/custom_ui/dataTable-toolbar"; import type { SearchFiltro } from "~/components/custom_ui/dataTable-toolbar";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import type { initialValues } from "~/forms/FormFlags";
import type { Flags } from "~/schemas/public/Flags"; import type { Flags } from "~/schemas/public/Flags";
export const FlagsTable = (props: { export const FlagsTable = (props: {
data: Flags[]; data: Flags[];
setOpenEdit: (status: boolean) => void; setOpenEdit: (status: boolean) => void;
setEditData: (data: initialValues | null) => void; setEditData: (data: Flags | null) => void;
}) => { }) => {
const { data, setOpenEdit, setEditData } = props; const { data, setOpenEdit, setEditData } = props;
@ -40,7 +39,11 @@ export const FlagsTable = (props: {
accessorKey: "value", accessorKey: "value",
cell: ({ row }) => { cell: ({ row }) => {
const data = row.original; const data = row.original;
return data.value === null ? "null" : data.value; return data.value ? (
<span className="text-success">Attivo</span>
) : (
<span>Inattivo</span>
);
}, },
enableHiding: false, enableHiding: false,
header: ({ column }) => ( header: ({ column }) => (

View file

@ -134,7 +134,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
}); });
const { mutateAsync: revalidate } = const { mutateAsync: revalidate } =
api.settings.revalidateAnnuncio.useMutation({ api.revalidation.revalidateAnnuncio.useMutation({
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); await utils.annunci.getAnnuncio.invalidate({ cod: data.codice });
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({ await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({
@ -144,7 +144,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
}, },
}); });
const { mutateAsync: update } = api.settings.updateAnnuncio.useMutation({ const { mutateAsync: update } = api.revalidation.updateAnnuncio.useMutation({
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnuncio.invalidate({ cod: data.codice }); await utils.annunci.getAnnuncio.invalidate({ cod: data.codice });
await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({ await utils.annunci.getAnnuncioById_rawImgUrls.invalidate({

View file

@ -9,16 +9,17 @@ import {
} from "~/components/custom_ui/form"; } from "~/components/custom_ui/form";
import Input from "~/components/custom_ui/input"; import Input from "~/components/custom_ui/input";
import { Button } from "~/components/ui/button"; import { Button } from "~/components/ui/button";
import { Switch } from "~/components/ui/switch";
import { useZodForm } from "~/lib/zodForm"; import { useZodForm } from "~/lib/zodForm";
import type { FlagsId } from "~/schemas/public/Flags"; import type { Flags, FlagsId } from "~/schemas/public/Flags";
export type initialValues = { export type initialValues = {
id: FlagsId; id: FlagsId;
value: string; value: string;
}; };
//TODO salvare flags come boolean //TODO salvare flags come boolean
type FormProps = { type FormProps = {
initialValues: initialValues | null; initialValues: Flags | null;
submitMutation: (values: initialValues) => void; submitMutation: (values: Flags) => void;
handleRemove: (id: FlagsId) => void; handleRemove: (id: FlagsId) => void;
}; };
export const FormFlags = ({ export const FormFlags = ({
@ -28,7 +29,7 @@ export const FormFlags = ({
}: FormProps) => { }: FormProps) => {
const Schema = z.object({ const Schema = z.object({
id: z.string(), id: z.string(),
value: z.string(), value: z.boolean(),
}); });
type FormValues = z.infer<typeof Schema>; type FormValues = z.infer<typeof Schema>;
@ -37,7 +38,7 @@ export const FormFlags = ({
if (!initialValues) { if (!initialValues) {
defaultValues = { defaultValues = {
id: "", id: "",
value: "", value: false,
}; };
} else { } else {
defaultValues = { defaultValues = {
@ -88,15 +89,15 @@ export const FormFlags = ({
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<div className="flex flex-wrap items-center gap-x-2"> <div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="value">Valore testuale</FormLabel> <FormLabel htmlFor="value">Attivo/Inattivo</FormLabel>
<FormMessage /> <FormMessage />
</div> </div>
<FormControl> <FormControl>
<Input <Switch
placeholder="" checked={field.value}
{...field} className="data-[state=checked]:bg-neutral-700"
id="value" id="value"
value={field.value} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
</FormItem> </FormItem>

View file

@ -37,7 +37,7 @@ export const FormPrezzo = ({
submitMutation, submitMutation,
}: FormPrezzoProps) => { }: FormPrezzoProps) => {
const { data: stringhe_condizioni } = const { data: stringhe_condizioni } =
api.settings.getStringheCondizioni.useQuery(); api.strings.getStringheCondizioni.useQuery();
const stringhe_condizioni_options = [ const stringhe_condizioni_options = [
"", "",

View file

@ -226,7 +226,7 @@ export async function getStaticProps(
const meta = await ssg.annunci.getAnnuncioMeta.fetch({ cod: cod }); const meta = await ssg.annunci.getAnnuncioMeta.fetch({ cod: cod });
const flag = await ssg.settings.GetFlagValue.fetch({ const flag = await ssg.flags.GetFlagValue.fetch({
id: "ANNUNCIO_INTERACTIONS_DISABLED", id: "ANNUNCIO_INTERACTIONS_DISABLED",
}); });
return { return {

View file

@ -18,19 +18,21 @@ import { api } from "~/utils/api";
const Admin_Annunci: NextPageWithLayout = () => { const Admin_Annunci: NextPageWithLayout = () => {
const { data, isLoading, refetch } = api.annunci.getAnnunciList.useQuery(); const { data, isLoading, refetch } = api.annunci.getAnnunciList.useQuery();
const utils = api.useUtils(); const utils = api.useUtils();
const { mutateAsync: update } = api.settings.updateAllAnnunci.useMutation({ const { mutateAsync: update } = api.revalidation.updateAllAnnunci.useMutation(
onSettled: async () => { {
await utils.annunci.getAnnunciList.invalidate(); onSettled: async () => {
toast.success( await utils.annunci.getAnnunciList.invalidate();
"La revalidazione dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.", toast.success(
{ "La revalidazione dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
duration: 5000, {
}, duration: 5000,
); },
);
},
}, },
}); );
const { mutateAsync: revalidate } = const { mutateAsync: revalidate } =
api.settings.revalidateAllAnnunci.useMutation({ api.revalidation.revalidateAllAnnunci.useMutation({
onSettled: async () => { onSettled: async () => {
await utils.annunci.getAnnunciList.invalidate(); await utils.annunci.getAnnunciList.invalidate();
toast.success("Revalidazione completata"); toast.success("Revalidazione completata");

View file

@ -21,7 +21,7 @@ import { generateSSGHelper } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const AdminBanners: NextPageWithLayout = () => { const AdminBanners: NextPageWithLayout = () => {
const { data, isLoading, refetch } = api.settings.getBannerAllData.useQuery(); const { data, isLoading, refetch } = api.banners.getBannerAllData.useQuery();
const [openEdit, setOpenEdit] = useState(false); const [openEdit, setOpenEdit] = useState(false);
const [editData, setEditData] = useState<Banners | null>(null); const [editData, setEditData] = useState<Banners | null>(null);
@ -87,7 +87,7 @@ export default AdminBanners;
export async function getServerSideProps() { export async function getServerSideProps() {
const helpers = generateSSGHelper(); const helpers = generateSSGHelper();
await helpers.settings.getBannerAllData.prefetch(); await helpers.banners.getBannerAllData.prefetch();
return { return {
props: { props: {
@ -110,36 +110,36 @@ const EditModal = ({
setOpen: (status: boolean) => void; setOpen: (status: boolean) => void;
}) => { }) => {
const utils = api.useUtils(); const utils = api.useUtils();
const { mutate: edit } = api.settings.updateBanner.useMutation({ const { mutate: edit } = api.banners.updateBanner.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getBannerAllData.invalidate(); await utils.banners.getBannerAllData.invalidate();
await utils.settings.getBannerData.invalidate(); await utils.banners.getBannerData.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: add } = api.settings.addBanner.useMutation({ const { mutate: add } = api.banners.addBanner.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getBannerAllData.invalidate(); await utils.banners.getBannerAllData.invalidate();
await utils.settings.getBannerData.invalidate(); await utils.banners.getBannerData.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: del } = api.settings.deleteBanner.useMutation({ const { mutate: del } = api.banners.deleteBanner.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getBannerAllData.invalidate(); await utils.banners.getBannerAllData.invalidate();
await utils.settings.getBannerData.invalidate(); await utils.banners.getBannerData.invalidate();
setOpen(false); setOpen(false);
}, },
}); });

View file

@ -22,7 +22,7 @@ import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const AdminEtichette: NextPageWithLayout = () => { const AdminEtichette: NextPageWithLayout = () => {
const { data, isLoading, refetch } = api.settings.getAllEtichette.useQuery(); const { data, isLoading, refetch } = api.etichette.getAllEtichette.useQuery();
const [openEdit, setOpenEdit] = useState(false); const [openEdit, setOpenEdit] = useState(false);
const [editData, setEditData] = useState<Etichette | null>(null); const [editData, setEditData] = useState<Etichette | null>(null);
@ -91,7 +91,7 @@ export const getServerSideProps = (async (context) => {
const helpers = await TrpcAuthedFetchingIstance({ access_token }); const helpers = await TrpcAuthedFetchingIstance({ access_token });
if (helpers) { if (helpers) {
await helpers.trpc.settings.getAllEtichette.prefetch(); await helpers.trpc.etichette.getAllEtichette.prefetch();
return { return {
props: { props: {
trpcState: helpers.trpc.dehydrate(), trpcState: helpers.trpc.dehydrate(),
@ -117,37 +117,37 @@ const EditModal = ({
setOpen: (status: boolean) => void; setOpen: (status: boolean) => void;
}) => { }) => {
const utils = api.useUtils(); const utils = api.useUtils();
const { mutate: edit } = api.settings.updateEtichetta.useMutation({ const { mutate: edit } = api.etichette.updateEtichetta.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getAllEtichette.invalidate(); await utils.etichette.getAllEtichette.invalidate();
await utils.chat.getChatEtichette.invalidate(); await utils.chat.getChatEtichette.invalidate();
await utils.chat.getActiveChats.invalidate(); await utils.chat.getActiveChats.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: add } = api.settings.addEtichetta.useMutation({ const { mutate: add } = api.etichette.addEtichetta.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getAllEtichette.invalidate(); await utils.etichette.getAllEtichette.invalidate();
await utils.chat.getChatEtichette.invalidate(); await utils.chat.getChatEtichette.invalidate();
await utils.chat.getActiveChats.invalidate(); await utils.chat.getActiveChats.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: del } = api.settings.removeEtichetta.useMutation({ const { mutate: del } = api.etichette.removeEtichetta.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getAllEtichette.invalidate(); await utils.etichette.getAllEtichette.invalidate();
await utils.chat.getChatEtichette.invalidate(); await utils.chat.getChatEtichette.invalidate();
await utils.chat.getActiveChats.invalidate(); await utils.chat.getActiveChats.invalidate();
setOpen(false); setOpen(false);

View file

@ -14,21 +14,22 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "~/components/ui/dialog"; } from "~/components/ui/dialog";
import { FormFlags, type initialValues } from "~/forms/FormFlags"; import { FormFlags } from "~/forms/FormFlags";
import type { NextPageWithLayout } from "~/pages/_app"; import type { NextPageWithLayout } from "~/pages/_app";
import type { Flags } from "~/schemas/public/Flags";
import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper"; import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const AdminFlags: NextPageWithLayout = () => { const AdminFlags: NextPageWithLayout = () => {
const { data, isLoading, refetch } = api.settings.GetFlags.useQuery(); const { data, isLoading, refetch } = api.flags.GetFlags.useQuery();
const [openEdit, setOpenEdit] = useState(false); const [openEdit, setOpenEdit] = useState(false);
const [editData, setEditData] = useState<initialValues | null>(null); const [editData, setEditData] = useState<Flags | null>(null);
const handleOpen = (status: boolean) => { const handleOpen = (status: boolean) => {
setOpenEdit(status); setOpenEdit(status);
}; };
const handleEdit = (data: initialValues | null) => { const handleEdit = (data: Flags | null) => {
setEditData(data); setEditData(data);
}; };
@ -89,7 +90,7 @@ export const getServerSideProps = (async (context) => {
const helpers = await TrpcAuthedFetchingIstance({ access_token }); const helpers = await TrpcAuthedFetchingIstance({ access_token });
if (helpers) { if (helpers) {
await helpers.trpc.settings.GetFlags.prefetch(); await helpers.trpc.flags.GetFlags.prefetch();
return { return {
props: { props: {
trpcState: helpers.trpc.dehydrate(), trpcState: helpers.trpc.dehydrate(),
@ -110,38 +111,38 @@ const EditModal = ({
open, open,
setOpen, setOpen,
}: { }: {
initial: initialValues | null; initial: Flags | null;
open: boolean; open: boolean;
setOpen: (status: boolean) => void; setOpen: (status: boolean) => void;
}) => { }) => {
const utils = api.useUtils(); const utils = api.useUtils();
const { mutate: edit } = api.settings.EditFlag.useMutation({ const { mutate: edit } = api.flags.EditFlag.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.GetFlags.invalidate(); await utils.flags.GetFlags.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: add } = api.settings.AddFlag.useMutation({ const { mutate: add } = api.flags.AddFlag.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.GetFlags.invalidate(); await utils.flags.GetFlags.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: remove } = api.settings.RemoveFlag.useMutation({ const { mutate: remove } = api.flags.RemoveFlag.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.GetFlags.invalidate(); await utils.flags.GetFlags.invalidate();
setOpen(false); setOpen(false);
}, },
}); });

View file

@ -22,7 +22,7 @@ import { TrpcAuthedFetchingIstance } from "~/server/utils/ssgHelper";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const AdminTestiStringhe: NextPageWithLayout = () => { const AdminTestiStringhe: NextPageWithLayout = () => {
const { data, isLoading, refetch } = api.settings.getStringhe.useQuery(); const { data, isLoading, refetch } = api.strings.getStringhe.useQuery();
const [openEdit, setOpenEdit] = useState(false); const [openEdit, setOpenEdit] = useState(false);
const [editData, setEditData] = useState<TestiEStringhe | null>(null); const [editData, setEditData] = useState<TestiEStringhe | null>(null);
@ -90,7 +90,7 @@ export const getServerSideProps = (async (context) => {
const helpers = await TrpcAuthedFetchingIstance({ access_token }); const helpers = await TrpcAuthedFetchingIstance({ access_token });
if (helpers) { if (helpers) {
await helpers.trpc.settings.getStringhe.prefetch(); await helpers.trpc.strings.getStringhe.prefetch();
return { return {
props: { props: {
trpcState: helpers.trpc.dehydrate(), trpcState: helpers.trpc.dehydrate(),
@ -117,33 +117,33 @@ const EditModal = ({
setOpen: (status: boolean) => void; setOpen: (status: boolean) => void;
}) => { }) => {
const utils = api.useUtils(); const utils = api.useUtils();
const { mutate: edit } = api.settings.updateStringa.useMutation({ const { mutate: edit } = api.strings.updateStringa.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getStringhe.invalidate(); await utils.strings.getStringhe.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: add } = api.settings.newStringa.useMutation({ const { mutate: add } = api.strings.newStringa.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getStringhe.invalidate(); await utils.strings.getStringhe.invalidate();
setOpen(false); setOpen(false);
}, },
}); });
const { mutate: del } = api.settings.deleteStringa.useMutation({ const { mutate: del } = api.strings.deleteStringa.useMutation({
onError: (error) => { onError: (error) => {
toast.error(error.message); toast.error(error.message);
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Successo"); toast.success("Successo");
await utils.settings.getStringhe.invalidate(); await utils.strings.getStringhe.invalidate();
setOpen(false); setOpen(false);
}, },
}); });

View file

@ -10,7 +10,7 @@ const PrivacyPolicy: NextPage = () => {
const key = ( const key = (
locale === "en" ? "PRIVACY_POLICY_ENG" : "PRIVACY_POLICY" locale === "en" ? "PRIVACY_POLICY_ENG" : "PRIVACY_POLICY"
) as TestiEStringheStingaId; ) as TestiEStringheStingaId;
const { data } = api.settings.getStringa.useQuery({ const { data } = api.strings.getStringa.useQuery({
stringaId: key, stringaId: key,
}); });
return ( return (
@ -37,7 +37,7 @@ export const getServerSideProps = (async (context) => {
const key = locale === "en" ? "PRIVACY_POLICY_ENG" : "PRIVACY_POLICY"; const key = locale === "en" ? "PRIVACY_POLICY_ENG" : "PRIVACY_POLICY";
const helpers = generateSSGHelper(); const helpers = generateSSGHelper();
await helpers.settings.getStringa.prefetch({ await helpers.strings.getStringa.prefetch({
stringaId: key as TestiEStringheStingaId, stringaId: key as TestiEStringheStingaId,
}); });
return { return {

View file

@ -15,7 +15,7 @@ type CondizioniProps = {
const CondizioniPage: NextPageWithLayout<CondizioniProps> = ({ const CondizioniPage: NextPageWithLayout<CondizioniProps> = ({
stringaId, stringaId,
}: CondizioniProps) => { }: CondizioniProps) => {
const { data, isLoading } = api.settings.getStringa.useQuery({ const { data, isLoading } = api.strings.getStringa.useQuery({
stringaId, stringaId,
}); });
@ -75,7 +75,7 @@ export const getServerSideProps = (async (context) => {
const helper = await TrpcAuthedFetchingIstance({ access_token }); const helper = await TrpcAuthedFetchingIstance({ access_token });
if (helper) { if (helper) {
await helper.trpc.settings.getStringa.prefetch({ await helper.trpc.strings.getStringa.prefetch({
stringaId: parsed.data, stringaId: parsed.data,
}); });

View file

@ -10,7 +10,7 @@ const Termini_Condizioni: NextPage = () => {
const key = ( const key = (
locale === "en" ? "TERMINI_CONDIZIONI_ENG" : "TERMINI_CONDIZIONI" locale === "en" ? "TERMINI_CONDIZIONI_ENG" : "TERMINI_CONDIZIONI"
) as TestiEStringheStingaId; ) as TestiEStringheStingaId;
const { data } = api.settings.getStringa.useQuery({ const { data } = api.strings.getStringa.useQuery({
stringaId: key, stringaId: key,
}); });
return ( return (
@ -36,7 +36,7 @@ export const getServerSideProps = (async (context) => {
const key = locale === "en" ? "TERMINI_CONDIZIONI_ENG" : "TERMINI_CONDIZIONI"; const key = locale === "en" ? "TERMINI_CONDIZIONI_ENG" : "TERMINI_CONDIZIONI";
const helpers = generateSSGHelper(); const helpers = generateSSGHelper();
await helpers.settings.getStringa.prefetch({ await helpers.strings.getStringa.prefetch({
stringaId: key as TestiEStringheStingaId, stringaId: key as TestiEStringheStingaId,
}); });
return { return {

View file

@ -10,7 +10,7 @@ export type FlagsId = string & { __brand: 'public.flags' };
export default interface FlagsTable { export default interface FlagsTable {
id: ColumnType<FlagsId, FlagsId, FlagsId>; id: ColumnType<FlagsId, FlagsId, FlagsId>;
value: ColumnType<string, string, string>; value: ColumnType<boolean, boolean | undefined, boolean>;
} }
export type Flags = Selectable<FlagsTable>; export type Flags = Selectable<FlagsTable>;

View file

@ -12,14 +12,18 @@ import { messagesSSERouter } from "~/server/api/routers/messages_sse";
import { pagamentiRouter } from "~/server/api/routers/pagamenti"; import { pagamentiRouter } from "~/server/api/routers/pagamenti";
import { prezziarioRouter } from "~/server/api/routers/prezziario"; import { prezziarioRouter } from "~/server/api/routers/prezziario";
import { servizioRouter } from "~/server/api/routers/servizio"; import { servizioRouter } from "~/server/api/routers/servizio";
import { settingsRouter } from "~/server/api/routers/settings";
import { statsRouter } from "~/server/api/routers/stats"; import { statsRouter } from "~/server/api/routers/stats";
import { storageRouter } from "~/server/api/routers/storage"; import { storageRouter } from "~/server/api/routers/storage";
import { stripeRouter } from "~/server/api/routers/stripe"; import { stripeRouter } from "~/server/api/routers/stripe";
import { testRouter } from "~/server/api/routers/test"; import { testRouter } from "~/server/api/routers/test";
import { usersRouter } from "~/server/api/routers/users"; import { usersRouter } from "~/server/api/routers/users";
import { createTRPCRouter } from "~/server/api/trpc"; import { createTRPCRouter } from "~/server/api/trpc";
import { bannersRouter } from "./routers/banners";
import { catastoRouter } from "./routers/catasto"; import { catastoRouter } from "./routers/catasto";
import { etichetteRouter } from "./routers/etichette";
import { flagsRouter } from "./routers/flags";
import { revalidationRouter } from "./routers/revalidation";
import { stringsRouter } from "./routers/strings";
import { syncRouter } from "./routers/sync"; import { syncRouter } from "./routers/sync";
//import { lazy } from '@trpc/server'; //import { lazy } from '@trpc/server';
@ -39,7 +43,6 @@ export const appRouter = createTRPCRouter({
pagamenti: pagamentiRouter, pagamenti: pagamentiRouter,
prezziario: prezziarioRouter, prezziario: prezziarioRouter,
servizio: servizioRouter, servizio: servizioRouter,
settings: settingsRouter,
stats: statsRouter, stats: statsRouter,
storage: storageRouter, storage: storageRouter,
stripe: stripeRouter, stripe: stripeRouter,
@ -47,5 +50,10 @@ export const appRouter = createTRPCRouter({
users: usersRouter, users: usersRouter,
sync: syncRouter, sync: syncRouter,
catasto: catastoRouter, catasto: catastoRouter,
banners: bannersRouter,
flags: flagsRouter,
etichette: etichetteRouter,
strings: stringsRouter,
revalidation: revalidationRouter,
}); });
export type AppRouter = typeof appRouter; export type AppRouter = typeof appRouter;

View file

@ -0,0 +1,81 @@
import { z } from "zod/v4";
import type { BannersIdbanner } from "~/schemas/public/Banners";
import {
adminProcedure,
createTRPCRouter,
publicProcedure,
} from "~/server/api/trpc";
import { db } from "~/server/db";
import {
addBanner,
deleteBanner,
getAllBanners,
getBanner,
updateBanner,
} from "~/server/services/banners.service";
export const bannersRouter = createTRPCRouter({
addBanner: adminProcedure
.input(
z.object({
color: z.string().nullable(),
cta_href: z.string().nullable(),
cta_icon: z.string().nullable(),
cta_text: z.string().nullable(),
has_cta: z.boolean(),
hide_duration: z.number().nullable(),
idbanner: z.custom<BannersIdbanner>(),
is_active: z.boolean(),
is_unskippable: z.boolean(),
show_private: z.boolean(),
show_public: z.boolean(),
testo: z.string().nullable(),
titolo: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await addBanner({ db, input });
}),
getBannerAllData: publicProcedure.query(async () => {
return await getAllBanners({ db });
}),
deleteBanner: adminProcedure
.input(z.object({ idbanner: z.custom<BannersIdbanner>() }))
.mutation(async ({ input }) => {
return await deleteBanner({ db, input });
}),
updateBanner: adminProcedure
.input(
z.object({
color: z.string().nullable(),
cta_href: z.string().nullable(),
cta_icon: z.string().nullable(),
cta_text: z.string().nullable(),
has_cta: z.boolean(),
hide_duration: z.number().nullable(),
idbanner: z.custom<BannersIdbanner>(),
is_active: z.boolean(),
is_unskippable: z.boolean(),
show_private: z.boolean(),
show_public: z.boolean(),
testo: z.string().nullable(),
titolo: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await updateBanner({ db, input });
}),
getBannerData: publicProcedure
.input(
z.object({
area_riservata: z.boolean(),
}),
)
.query(async ({ input }) => {
return await getBanner({
area_riservata: input.area_riservata,
db,
});
}),
});

View file

@ -0,0 +1,54 @@
import { z } from "zod/v4";
import { adminProcedure, createTRPCRouter } from "~/server/api/trpc";
import {
addEtichetta,
getAllEtichette,
removeEtichetta,
updateEtichetta,
} from "~/server/controllers/etichette.controller";
import { db } from "~/server/db";
import { zEtichettaId } from "~/server/utils/zod_types";
export const etichetteRouter = createTRPCRouter({
addEtichetta: adminProcedure
.input(
z.object({
color_hex: z.string().max(7),
title: z.string(),
}),
)
.mutation(async ({ input }) => {
return await addEtichetta({
color_hex: input.color_hex,
db,
title: input.title,
});
}),
getAllEtichette: adminProcedure.query(async () => {
return await getAllEtichette({ db });
}),
removeEtichetta: adminProcedure
.input(z.object({ id_etichetta: zEtichettaId }))
.mutation(async ({ input }) => {
return await removeEtichetta({
db,
etichettaid: input.id_etichetta,
});
}),
updateEtichetta: adminProcedure
.input(
z.object({
color_hex: z.string().max(7),
id_etichetta: zEtichettaId,
title: z.string(),
}),
)
.mutation(async ({ input }) => {
return await updateEtichetta({
color_hex: input.color_hex,
db,
etichettaid: input.id_etichetta,
title: input.title,
});
}),
});

View file

@ -0,0 +1,58 @@
import { z } from "zod/v4";
import {
adminProcedure,
createTRPCRouter,
publicProcedure,
} from "~/server/api/trpc";
import {
AddFlagHandler,
EditFlagHandler,
GetFlagHandler,
GetFlagValueHandler,
RemoveFlagHandler,
} from "~/server/controllers/flags.controller";
import { db } from "~/server/db";
import { zFlagsId } from "~/server/utils/zod_types";
export const flagsRouter = createTRPCRouter({
AddFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
value: z.boolean(),
}),
)
.mutation(async ({ input }) => {
return await AddFlagHandler({ db, input });
}),
EditFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
value: z.boolean(),
}),
)
.mutation(async ({ input }) => {
return await EditFlagHandler({ db, input });
}),
GetFlags: adminProcedure.query(async () => {
return await GetFlagHandler({ db });
}),
GetFlagValue: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return await GetFlagValueHandler({ db, id: input.id });
}),
RemoveFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
}),
)
.mutation(async ({ input }) => {
return await RemoveFlagHandler({ db, id: input.id });
}),
});

View file

@ -0,0 +1,133 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod/v4";
import { env } from "~/env";
import { adminProcedure, createTRPCRouter } from "~/server/api/trpc";
import { getCodici_AnnunciHandler } from "~/server/controllers/annunci.controller";
import {
revalidate,
revalidateMultiple,
} from "~/server/utils/revalidationHelper";
export const revalidationRouter = createTRPCRouter({
revalidateAllAnnunci: adminProcedure.mutation(async () => {
try {
const annunciOnline = await getCodici_AnnunciHandler();
const { success, failed } = await revalidateMultiple(
annunciOnline.map((cod) => `/annuncio/${cod}`),
);
//console.log(`Successfully revalidated pages: ${success.join(", ")}`);
if (success.length === 0) {
console.log("No annunci were revalidated.");
}
if (failed.length > 0) {
failed.forEach(({ path, error }) => {
console.error(`Failed to revalidate ${path}: ${error}`);
});
}
return {
status: "success",
};
} catch (err) {
console.error("Revalidation error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Revalidation failed",
cause: err,
});
}
}),
revalidateAnnuncio: adminProcedure
.input(
z.object({
cod: z.string(),
}),
)
.mutation(async ({ input }) => {
try {
await revalidate(`/annuncio/${input.cod}`);
return {
status: "success",
};
} catch (err) {
console.error("Revalidation error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Revalidation failed",
cause: err,
});
}
}),
updateAllAnnunci: adminProcedure.mutation(async () => {
try {
const response = await fetch(`${env.BACKENDSERVER_URL}/update`);
if (!response.ok) {
const errorData = await response.text().catch(() => "Unknown error");
throw new Error(
`Update failed with status ${response.status}: ${errorData}`,
);
}
const data = await response.json().catch(() => ({}));
const annunciOnline = await getCodici_AnnunciHandler();
const { success, failed } = await revalidateMultiple(
annunciOnline.map((cod) => `/annuncio/${cod}`),
);
if (success.length === 0) {
console.log("No annunci were revalidated.");
}
//console.log(`Successfully revalidated pages: ${success.join(", ")}`);
if (failed.length > 0) {
failed.forEach(({ path, error }) => {
console.error(`Failed to revalidate ${path}: ${error}`);
});
}
return {
status: "success",
details: data,
};
} catch (err) {
console.error("Update error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Update failed",
cause: err,
});
}
}),
updateAnnuncio: adminProcedure
.input(
z.object({
cod: z.string(),
}),
)
.mutation(async ({ input }) => {
try {
const response = await fetch(
`${env.BACKENDSERVER_URL}/update-cod/${input.cod}`,
);
if (!response.ok) {
const errorData = await response.text().catch(() => "Unknown error");
throw new Error(
`Update failed with status ${response.status}: ${errorData}`,
);
}
const data = await response.json().catch(() => ({}));
await revalidate(`/annuncio/${input.cod}`);
return {
status: "success",
details: data,
};
} catch (err) {
console.error("Update error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Update failed",
cause: err,
});
}
}),
});

View file

@ -1,379 +0,0 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod/v4";
import { env } from "~/env";
import type { BannersIdbanner } from "~/schemas/public/Banners";
import {
adminProcedure,
createTRPCRouter,
publicProcedure,
} from "~/server/api/trpc";
import { getCodici_AnnunciHandler } from "~/server/controllers/annunci.controller";
import {
addEtichetta,
getAllEtichette,
removeEtichetta,
updateEtichetta,
} from "~/server/controllers/etichette.controller";
import {
AddFlagHandler,
EditFlagHandler,
GetFlagHandler,
GetFlagValueHandler,
RemoveFlagHandler,
} from "~/server/controllers/flags.controller";
import { db } from "~/server/db";
import {
addBanner,
deleteBanner,
getAllBanners,
getBanner,
updateBanner,
} from "~/server/services/banners.service";
import {
deleteStringa,
getStringa,
getStringhe,
getStringheFiltered,
newStringa,
updateStringhe,
} from "~/server/services/testi_stringhe.service";
import {
revalidate,
revalidateMultiple,
} from "~/server/utils/revalidationHelper";
import {
zEtichettaId,
zFlagsId,
zTestiEStringheStingaId,
} from "~/server/utils/zod_types";
export const settingsRouter = createTRPCRouter({
AddFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
value: z.string(),
}),
)
.mutation(async ({ input }) => {
return await AddFlagHandler({ db, input });
}),
addBanner: adminProcedure
.input(
z.object({
color: z.string().nullable(),
cta_href: z.string().nullable(),
cta_icon: z.string().nullable(),
cta_text: z.string().nullable(),
has_cta: z.boolean(),
hide_duration: z.number().nullable(),
idbanner: z.custom<BannersIdbanner>(),
is_active: z.boolean(),
is_unskippable: z.boolean(),
show_private: z.boolean(),
show_public: z.boolean(),
testo: z.string().nullable(),
titolo: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await addBanner({ db, input });
}),
addEtichetta: adminProcedure
.input(
z.object({
color_hex: z.string().max(7),
title: z.string(),
}),
)
.mutation(async ({ input }) => {
return await addEtichetta({
color_hex: input.color_hex,
db,
title: input.title,
});
}),
deleteBanner: adminProcedure
.input(z.object({ idbanner: z.custom<BannersIdbanner>() }))
.mutation(async ({ input }) => {
return await deleteBanner({ db, input });
}),
deleteStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
}),
)
.mutation(async ({ input }) => {
return await deleteStringa({
db,
stringaId: input.stringaId,
});
}),
EditFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
value: z.string(),
}),
)
.mutation(async ({ input }) => {
return await EditFlagHandler({ db, input });
}),
// Flags routes
GetFlags: adminProcedure.query(async () => {
return await GetFlagHandler({ db });
}),
GetFlagValue: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return await GetFlagValueHandler({ db, id: input.id });
}),
// Etichette routes
getAllEtichette: adminProcedure.query(async () => {
return await getAllEtichette({ db });
}),
getBannerAllData: publicProcedure.query(async () => {
return await getAllBanners({ db });
}),
// Banner routes
getBannerData: publicProcedure
.input(
z.object({
area_riservata: z.boolean(),
}),
)
.query(async ({ input }) => {
return await getBanner({
area_riservata: input.area_riservata,
db,
});
}),
getStringa: publicProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
}),
)
.query(async ({ input }) => {
return await getStringa({
db,
stringaId: input.stringaId,
});
}),
// Testi e stringhe routes
getStringhe: adminProcedure.query(async () => {
return await getStringhe({ db });
}),
getStringheCondizioni: adminProcedure.query(async () => {
return await getStringheFiltered({ contains: "CONDIZIONI", db });
}),
newStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
stringaValue: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await newStringa({
db,
stringaId: input.stringaId,
stringaValue: input.stringaValue,
});
}),
RemoveFlag: adminProcedure
.input(
z.object({
id: zFlagsId,
}),
)
.mutation(async ({ input }) => {
return await RemoveFlagHandler({ db, id: input.id });
}),
removeEtichetta: adminProcedure
.input(z.object({ id_etichetta: zEtichettaId }))
.mutation(async ({ input }) => {
return await removeEtichetta({
db,
etichettaid: input.id_etichetta,
});
}),
updateBanner: adminProcedure
.input(
z.object({
color: z.string().nullable(),
cta_href: z.string().nullable(),
cta_icon: z.string().nullable(),
cta_text: z.string().nullable(),
has_cta: z.boolean(),
hide_duration: z.number().nullable(),
idbanner: z.custom<BannersIdbanner>(),
is_active: z.boolean(),
is_unskippable: z.boolean(),
show_private: z.boolean(),
show_public: z.boolean(),
testo: z.string().nullable(),
titolo: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await updateBanner({ db, input });
}),
updateEtichetta: adminProcedure
.input(
z.object({
color_hex: z.string().max(7),
id_etichetta: zEtichettaId,
title: z.string(),
}),
)
.mutation(async ({ input }) => {
return await updateEtichetta({
color_hex: input.color_hex,
db,
etichettaid: input.id_etichetta,
title: input.title,
});
}),
updateStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
stringaValue: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await updateStringhe({
db,
stringaId: input.stringaId,
stringaValue: input.stringaValue,
});
}),
revalidateAllAnnunci: adminProcedure.mutation(async () => {
try {
const annunciOnline = await getCodici_AnnunciHandler();
const { success, failed } = await revalidateMultiple(
annunciOnline.map((cod) => `/annuncio/${cod}`),
);
//console.log(`Successfully revalidated pages: ${success.join(", ")}`);
if (success.length === 0) {
console.log("No annunci were revalidated.");
}
if (failed.length > 0) {
failed.forEach(({ path, error }) => {
console.error(`Failed to revalidate ${path}: ${error}`);
});
}
return {
status: "success",
};
} catch (err) {
console.error("Revalidation error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Revalidation failed",
cause: err,
});
}
}),
revalidateAnnuncio: adminProcedure
.input(
z.object({
cod: z.string(),
}),
)
.mutation(async ({ input }) => {
try {
await revalidate(`/annuncio/${input.cod}`);
return {
status: "success",
};
} catch (err) {
console.error("Revalidation error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Revalidation failed",
cause: err,
});
}
}),
updateAllAnnunci: adminProcedure.mutation(async () => {
try {
const response = await fetch(`${env.BACKENDSERVER_URL}/update`);
if (!response.ok) {
const errorData = await response.text().catch(() => "Unknown error");
throw new Error(
`Update failed with status ${response.status}: ${errorData}`,
);
}
const data = await response.json().catch(() => ({}));
const annunciOnline = await getCodici_AnnunciHandler();
const { success, failed } = await revalidateMultiple(
annunciOnline.map((cod) => `/annuncio/${cod}`),
);
if (success.length === 0) {
console.log("No annunci were revalidated.");
}
//console.log(`Successfully revalidated pages: ${success.join(", ")}`);
if (failed.length > 0) {
failed.forEach(({ path, error }) => {
console.error(`Failed to revalidate ${path}: ${error}`);
});
}
return {
status: "success",
details: data,
};
} catch (err) {
console.error("Update error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Update failed",
cause: err,
});
}
}),
updateAnnuncio: adminProcedure
.input(
z.object({
cod: z.string(),
}),
)
.mutation(async ({ input }) => {
try {
const response = await fetch(
`${env.BACKENDSERVER_URL}/update-cod/${input.cod}`,
);
if (!response.ok) {
const errorData = await response.text().catch(() => "Unknown error");
throw new Error(
`Update failed with status ${response.status}: ${errorData}`,
);
}
const data = await response.json().catch(() => ({}));
await revalidate(`/annuncio/${input.cod}`);
return {
status: "success",
details: data,
};
} catch (err) {
console.error("Update error:", err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: err instanceof Error ? err.message : "Update failed",
cause: err,
});
}
}),
});

View file

@ -0,0 +1,78 @@
import { z } from "zod/v4";
import {
adminProcedure,
createTRPCRouter,
publicProcedure,
} from "~/server/api/trpc";
import { db } from "~/server/db";
import {
deleteStringa,
getStringa,
getStringhe,
getStringheFiltered,
newStringa,
updateStringhe,
} from "~/server/services/testi_stringhe.service";
import { zTestiEStringheStingaId } from "~/server/utils/zod_types";
export const stringsRouter = createTRPCRouter({
getStringa: publicProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
}),
)
.query(async ({ input }) => {
return await getStringa({
db,
stringaId: input.stringaId,
});
}),
getStringhe: adminProcedure.query(async () => {
return await getStringhe({ db });
}),
getStringheCondizioni: adminProcedure.query(async () => {
return await getStringheFiltered({ contains: "CONDIZIONI", db });
}),
deleteStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
}),
)
.mutation(async ({ input }) => {
return await deleteStringa({
db,
stringaId: input.stringaId,
});
}),
newStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
stringaValue: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await newStringa({
db,
stringaId: input.stringaId,
stringaValue: input.stringaValue,
});
}),
updateStringa: adminProcedure
.input(
z.object({
stringaId: zTestiEStringheStingaId,
stringaValue: z.string().nullable(),
}),
)
.mutation(async ({ input }) => {
return await updateStringhe({
db,
stringaId: input.stringaId,
stringaValue: input.stringaValue,
});
}),
});

View file

@ -1,5 +1,5 @@
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import type { FlagsId } from "~/schemas/public/Flags"; import type { Flags, FlagsId } from "~/schemas/public/Flags";
import type { Querier } from "~/server/db"; import type { Querier } from "~/server/db";
export const EditFlagHandler = async ({ export const EditFlagHandler = async ({
@ -7,10 +7,7 @@ export const EditFlagHandler = async ({
input, input,
}: { }: {
db: Querier; db: Querier;
input: { input: Flags;
id: FlagsId;
value: string;
};
}) => { }) => {
try { try {
return await db return await db
@ -83,10 +80,7 @@ export const AddFlagHandler = async ({
input, input,
}: { }: {
db: Querier; db: Querier;
input: { input: Flags;
id: FlagsId;
value: string;
};
}) => { }) => {
try { try {
await db await db

View file

@ -133,9 +133,34 @@ async function sendSMS(auth: Auth, smsData: SMSData) {
export const SendMessage = async (data: MinimalSMSData) => { export const SendMessage = async (data: MinimalSMSData) => {
const smsFlag = await GetFlagValueHandler({ const smsFlag = await GetFlagValueHandler({
db: db, db: db,
id: "SMS_OFF", id: "SMS_ENABLED",
}); });
if (smsFlag === "true") { if (smsFlag) {
try {
const auth = await login(env.SKEBBY_USER, env.SKEBBY_PASS);
await sendSMS(auth, {
...data,
message_type: MessageType.HIGH_QUALITY,
sender: "InfoAlloggi",
});
} catch (error) {
console.error("Error:", error);
await NewMail({
template: {
mailType: "generic",
props: {
testo: `Errore durante l'invio dell'SMS: to:${data.recipient.join(", ")} Mgs:${data.message}; ${error instanceof Error ? error.message : String(error)}`,
title: "Errore invio SMS",
},
},
mail: {
subject: "Errore invio SMS",
to: "web@infoalloggi.it",
},
});
}
} else {
console.warn( console.warn(
`SMS sending is disabled to:${data.recipient.join(", ")} Mgs:${data.message}`, `SMS sending is disabled to:${data.recipient.join(", ")} Mgs:${data.message}`,
); );
@ -144,28 +169,4 @@ export const SendMessage = async (data: MinimalSMSData) => {
success: true, success: true,
}; };
} }
try {
const auth = await login(env.SKEBBY_USER, env.SKEBBY_PASS);
await sendSMS(auth, {
...data,
message_type: MessageType.HIGH_QUALITY,
sender: "InfoAlloggi",
});
} catch (error) {
console.error("Error:", error);
await NewMail({
template: {
mailType: "generic",
props: {
testo: `Errore durante l'invio dell'SMS: to:${data.recipient.join(", ")} Mgs:${data.message}; ${error instanceof Error ? error.message : String(error)}`,
title: "Errore invio SMS",
},
},
mail: {
subject: "Errore invio SMS",
to: "web@infoalloggi.it",
},
});
}
}; };

View file

@ -189,9 +189,9 @@ export const genMail = async ({ ...mail }: MailsTemplates) => {
export const NewMail = async ({ template, userId, mail }: NewMailProps) => { export const NewMail = async ({ template, userId, mail }: NewMailProps) => {
const emailFlag = await GetFlagValueHandler({ const emailFlag = await GetFlagValueHandler({
db: db, db: db,
id: "EMAIL_OFF", id: "EMAIL_ENABLED",
}); });
if (emailFlag === "false") { if (emailFlag) {
try { try {
if (template) { if (template) {
const { html } = await genMail({ ...template }); const { html } = await genMail({ ...template });