warehouse locations
This commit is contained in:
@ -9,6 +9,7 @@ import FileUploadWithPreview from 'components/FileUploadWithPreview ';
|
||||
|
||||
import ProtectedRoute, { serverSideAuth } from "../../components/protectedRoute";
|
||||
import { UserRole } from "@prisma/client";
|
||||
import { Input } from '@mui/base';
|
||||
|
||||
const common = require('src/helpers/common');
|
||||
|
||||
@ -67,6 +68,7 @@ export default function LocationForm() {
|
||||
address: "",
|
||||
isActive: true,
|
||||
});
|
||||
const [isRawHtml, setIsRawHtml] = useState(false);
|
||||
|
||||
// const [isEdit, setIsEdit] = useState(false);
|
||||
|
||||
@ -178,6 +180,13 @@ export default function LocationForm() {
|
||||
<label className="label" htmlFor="isActive">Активна</label>
|
||||
</div>
|
||||
</div>
|
||||
{/* is on main menu */}
|
||||
<div className="mb-4">
|
||||
<div className="form-check">
|
||||
<input className="checkbox form-input" type="checkbox" id="isOnMainMenu" name="isOnMainMenu" onChange={handleChange} checked={location.isOnMainMenu} autoComplete="off" />
|
||||
<label className="label" htmlFor="isOnMainMenu">Покажи в главното меню</label>
|
||||
</div>
|
||||
</div>
|
||||
{/* backupLocation */}
|
||||
<div className="mb-4">
|
||||
<label className="label" htmlFor="backupLocation">При дъжд и лошо време</label>
|
||||
@ -238,12 +247,50 @@ export default function LocationForm() {
|
||||
|
||||
<label className="label" htmlFor="content">Content</label>
|
||||
|
||||
<TextEditor
|
||||
ref={quillRef}
|
||||
value={content}
|
||||
onChange={setContent}
|
||||
placeholder="Описание на локацията. Снимки"
|
||||
prefix={`location-${router.query.id}`} />
|
||||
|
||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" ">
|
||||
<label className="label" htmlFor="backupLocation">Admin Edit Location HTML</label>
|
||||
<div className="field mb-4">
|
||||
<label className="switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isRawHtml}
|
||||
onChange={(e) => {
|
||||
setIsRawHtml(e.target.checked);
|
||||
}}
|
||||
/>
|
||||
<span className="slider round"></span>
|
||||
<span className="ml-2">Edit Raw HTML</span>
|
||||
|
||||
</label>
|
||||
{isRawHtml && <>
|
||||
<label className="label" htmlFor="backupLocation">Admin Edit Location HTML</label>
|
||||
<textarea
|
||||
className="w-full min-h-[200px] p-3 border rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-800 dark:border-gray-700 dark:text-gray-200 font-mono resize-y"
|
||||
placeholder="HTML Content"
|
||||
id="contentHTML_Raw"
|
||||
name="backupLocation"
|
||||
// onChange={handleChange}
|
||||
value={content}
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
/>
|
||||
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</ProtectedRoute>
|
||||
{!isRawHtml && <>
|
||||
<TextEditor
|
||||
ref={quillRef}
|
||||
value={content}
|
||||
onChange={setContent}
|
||||
placeholder="Описание на локацията. Снимки"
|
||||
prefix={`location-${router.query.id}`} />
|
||||
|
||||
</>}
|
||||
|
||||
|
||||
</>)}
|
||||
</div>
|
||||
<div className="panel-actions pt-12">
|
||||
@ -270,3 +317,4 @@ export default function LocationForm() {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,20 +112,35 @@ export default function Sidebar({ isSidebarOpen, toggleSidebar }) {
|
||||
useEffect(() => {
|
||||
const fetchLocations = async () => {
|
||||
try {
|
||||
if (session) { // Don't fetch locations if the user is not authenticated
|
||||
// if (session)
|
||||
{ // Don't fetch locations if the user is not authenticated
|
||||
|
||||
const response = await axiosInstance.get('/api/data/locations'); // Adjust the API endpoint as needed
|
||||
const locationsData = response.data
|
||||
.filter(location => location.isActive === true)
|
||||
const subMenuLocations = response.data
|
||||
.filter(location => location.isActive === true && location.isOnMainMenu === false)
|
||||
.map(location => ({
|
||||
text: location.name,
|
||||
url: `/cart/locations/${location.id}`,
|
||||
isOnMainMenu: location.isOnMainMenu,
|
||||
}));
|
||||
const mainMenuLocations = response.data.filter(l => l.isOnMainMenu === true)
|
||||
.map(location => ({
|
||||
key: location.name,
|
||||
text: t('location.' + location.name + '.menu') || location.name,
|
||||
url: location.url,
|
||||
}));
|
||||
|
||||
console.log("locationsData: ", response.data);
|
||||
console.log("subMenuLocations: ", subMenuLocations);
|
||||
console.log("mainMenuLocations: ", mainMenuLocations);
|
||||
// Find the "Locations" menu item and populate its children with locationsData
|
||||
const menuIndex = sidemenu.findIndex(item => item.id === "locations");
|
||||
if (menuIndex !== -1) {
|
||||
sidemenu[menuIndex].children = locationsData;
|
||||
sidemenu[menuIndex].children = subMenuLocations;
|
||||
}
|
||||
// insert main menu items after the locations (sidemenu[menuIndex+1])
|
||||
|
||||
sidemenu.splice(menuIndex + 1, 0, ...mainMenuLocations);
|
||||
//setLocations(locationsData); // Optional, if you need to use locations elsewhere
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -34,6 +34,11 @@ const sidemenu = [
|
||||
collapsable: true,
|
||||
url: "/cart/locations",
|
||||
},
|
||||
{
|
||||
id: "warehouse",
|
||||
text: "Склад",
|
||||
url: "/cart/locations/warehouse",
|
||||
},
|
||||
{
|
||||
id: "cart-report",
|
||||
text: "Отчет",
|
||||
|
@ -37,7 +37,8 @@
|
||||
"location": {
|
||||
"warehouse": {
|
||||
"description": "- снимки как да се поставят количките\n- снимка с код за катинар\nвсеки може да всима/връща\n- преди да влизаме трябва да почистим краката.\n- зареждаме/почистваме извън\n- влизане/озлизане няма код\n- влизане/излизане има код",
|
||||
"title": "СНЛАД"
|
||||
"title": "СKЛАД",
|
||||
"menu": "СKЛАД"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,12 +57,14 @@ const ViewLocationPage: React.FC<ViewLocationPageProps> = ({ location }) => {
|
||||
{location.name}
|
||||
</button>
|
||||
{/* Backup Location Tab */}
|
||||
<button
|
||||
className={`tab flex-1 text-lg py-2 px-4 ${activeTab === 'backupLocation' ? 'border-b-4 border-blue-500 text-blue-600 font-semibold' : 'text-gray-600 hover:text-blue-500'}`}
|
||||
onClick={() => handleTabChange('backupLocation')}
|
||||
>
|
||||
При лошо време: <strong>{location.backupLocationName}</strong>
|
||||
</button>
|
||||
{location.backupLocationId !== null && (
|
||||
<button
|
||||
className={`tab flex-1 text-lg py-2 px-4 ${activeTab === 'backupLocation' ? 'border-b-4 border-blue-500 text-blue-600 font-semibold' : 'text-gray-600 hover:text-blue-500'}`}
|
||||
onClick={() => handleTabChange('backupLocation')}
|
||||
>
|
||||
При лошо време: <strong>{location.backupLocationName}</strong>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Carousel */}
|
||||
@ -98,6 +100,8 @@ const ViewLocationPage: React.FC<ViewLocationPageProps> = ({ location }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const common = require("../../../src/helpers/common");
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const axios = await axiosServer(context);
|
||||
|
||||
@ -126,17 +130,19 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
const { data: location } = await axios.get(
|
||||
`${process.env.NEXT_PUBLIC_PUBLIC_URL}/api/data/locations/${context.params.id}`
|
||||
);
|
||||
const prismaClient = common.getPrismaClient();
|
||||
const location = await getLocation(prismaClient, context);
|
||||
location.content = replacePlaceholders(location.content);
|
||||
|
||||
if (location.backupLocationId !== null) {
|
||||
const { data: backupLocation } = await axios.get(
|
||||
process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/locations/" + location.backupLocationId
|
||||
);
|
||||
// const { data: backupLocation } = await axios.get(
|
||||
// process.env.NEXT_PUBLIC_PUBLIC_URL + "/api/data/locations/" + location.backupLocationId
|
||||
// );
|
||||
const backupLocation = await prismaClient.location.findFirst({
|
||||
where: {
|
||||
id: location.backupLocationId,
|
||||
},
|
||||
});
|
||||
location.backupLocationName = backupLocation.name;
|
||||
location.backupLocationContent = backupLocation ? replacePlaceholders(backupLocation.content) : "";
|
||||
location.backupLocationImages = backupLocation ? [backupLocation.picture1, backupLocation.picture2, backupLocation.picture3].filter(Boolean) : [];
|
||||
@ -151,4 +157,30 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
};
|
||||
};
|
||||
|
||||
async function getLocation(prismaClient, context) {
|
||||
// Try to parse the ID as a number
|
||||
const numericId = parseInt(context.params.id);
|
||||
let location;
|
||||
|
||||
// If it's a valid number, search by ID
|
||||
if (!isNaN(numericId)) {
|
||||
location = await prismaClient.location.findFirst({
|
||||
where: {
|
||||
id: numericId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If no location found by ID or if ID is not numeric, search by name
|
||||
if (!location) {
|
||||
location = await prismaClient.location.findFirst({
|
||||
where: {
|
||||
name: context.params.id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
export default ViewLocationPage;
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `location` ADD COLUMN `isOnMainMenu` BOOLEAN NOT NULL DEFAULT false;
|
@ -231,6 +231,7 @@ model Location {
|
||||
backupLocationId Int?
|
||||
backupLocation Location? @relation("BackupLocation", fields: [backupLocationId], references: [id])
|
||||
BackupForLocations Location[] @relation("BackupLocation")
|
||||
isOnMainMenu Boolean @default(false)
|
||||
|
||||
@@map("Location")
|
||||
}
|
||||
|
BIN
public/content/warehouse/1.jpg
Normal file
BIN
public/content/warehouse/1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 234 KiB |
BIN
public/content/warehouse/2.jpg
Normal file
BIN
public/content/warehouse/2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 MiB |
BIN
public/content/warehouse/3.jpg
Normal file
BIN
public/content/warehouse/3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 MiB |
BIN
public/content/warehouse/4.jpg
Normal file
BIN
public/content/warehouse/4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
BIN
public/content/warehouse/5.jpg
Normal file
BIN
public/content/warehouse/5.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
BIN
public/content/warehouse/6.jpg
Normal file
BIN
public/content/warehouse/6.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 862 KiB |
Reference in New Issue
Block a user