Skip to content

Instantly share code, notes, and snippets.

@adrianhajdin
Last active April 22, 2024 15:29
Show Gist options
  • Save adrianhajdin/c9e83f0fb1dfcf238dae0cc68a90ba82 to your computer and use it in GitHub Desktop.
Save adrianhajdin/c9e83f0fb1dfcf238dae0cc68a90ba82 to your computer and use it in GitHub Desktop.
Build and Deploy a Full Stack MERN Dashboard App With CRUD, Auth, and Charts Using Refine
import { ApexOptions } from 'apexcharts';
export const TotalRevenueSeries = [
{
name: 'Last Month',
data: [183, 124, 115, 85, 143, 143, 96],
},
{
name: 'Running Month',
data: [95, 84, 72, 44, 108, 108, 47],
},
];
export const TotalRevenueOptions: ApexOptions = {
chart: {
type: 'bar',
toolbar: {
show: false,
},
},
colors: ['#475BE8', '#CFC8FF'],
plotOptions: {
bar: {
borderRadius: 4,
horizontal: false,
columnWidth: '55%',
},
},
dataLabels: {
enabled: false,
},
grid: {
show: false,
},
stroke: {
colors: ['transparent'],
width: 4,
},
xaxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
},
yaxis: {
title: {
text: '$ (thousands)',
},
},
fill: {
opacity: 1,
},
legend: {
position: 'top',
horizontalAlign: 'right',
},
tooltip: {
y: {
formatter(val: number) {
return `$ ${val} thousands`;
},
},
},
};
import { Email, Phone, Place } from '@mui/icons-material';
import { Box, Stack, Typography } from '@pankod/refine-mui';
import { ProfileProps, PropertyProps } from 'interfaces/common';
import PropertyCard from './PropertyCard';
function checkImage(url: any) {
let img = new Image();
img.src = url;
return img.width !== 0 && img.height !== 0;
}
const Profile = ({ type, name, avatar, email, properties }: ProfileProps) => (
<Box>
<Typography fontSize={25} fontWeight={700} color="#11142D">{type} Profile</Typography>
<Box
mt="20px"
borderRadius="15px"
padding="20px"
bgcolor="#FCFCFC"
>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
gap: 2.5,
}}
>
<img
src="https://images.unsplash.com/photo-1618005198919-d3d4b5a92ead?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1374&q=80"
width={340}
height={320}
alt="abstract"
className="my_profile-bg"
/>
<Box
flex={1}
sx={{ marginTop: { md: '58px' }, marginLeft: { xs: '20px', md: '0px' } }}
>
<Box flex={1} display="flex" flexDirection={{ xs: 'column', md: 'row' }} gap="20px">
<img
src={checkImage(avatar) ? avatar : "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/User-avatar.svg/2048px-User-avatar.svg.png"}
width={78}
height={78}
alt="user_profile"
className="my_profile_user-img"
/>
<Box flex={1} display="flex" flexDirection="column" justifyContent="space-between" gap="30px">
<Stack direction="column">
<Typography fontSize={22} fontWeight={600} color="#11142D">{name}</Typography>
<Typography fontSize={16} color="#808191">Realestate Agent</Typography>
</Stack>
<Stack direction="column" gap="30px">
<Stack gap="15px">
<Typography fontSize={14} fontWeight={500} color="#808191">Address</Typography>
<Box display="flex" flexDirection="row" alignItems="center" gap="10px">
<Place sx={{ color: '#11142D' }} />
<Typography fontSize={14} color="#11142D">4517 Washington Ave. Manchaster, Kentucky 39495</Typography>
</Box>
</Stack>
<Stack direction="row" flexWrap="wrap" gap="20px" pb={4}>
<Stack flex={1} gap="15px">
<Typography fontSize={14} fontWeight={500} color="#808191">Phone Number</Typography>
<Box display="flex" flexDirection="row" alignItems="center" gap="10px">
<Phone sx={{ color: '#11142D' }} />
<Typography fontSize={14} color="#11142D" noWrap>+0123 456 7890</Typography>
</Box>
</Stack>
<Stack flex={1} gap="15px">
<Typography fontSize={14} fontWeight={500} color="#808191">Email</Typography>
<Box display="flex" flexDirection="row" alignItems="center" gap="10px">
<Email sx={{ color: '#11142D' }} />
<Typography fontSize={14} color="#11142D">{email}</Typography>
</Box>
</Stack>
</Stack>
</Stack>
</Box>
</Box>
</Box>
</Box>
</Box>
{properties.length > 0 && (
<Box
mt={2.5}
borderRadius="15px"
padding="20px"
bgcolor="#FCFCFC"
>
<Typography fontSize={18} fontWeight={600} color="#11142D">{type} Properties</Typography>
<Box
mt={2.5}
sx={{
display: 'flex',
flexWrap: 'wrap',
gap: 2.5,
}}
>
{properties?.map((property: PropertyProps) => (
<PropertyCard key={property._id} id={property._id}
title={property.title}
location={property.location}
price={property.price}
photo={property.photo}
/>
))}
</Box>
</Box>
)}
</Box>
);
export default Profile;
// common
import Profile from './common/Profile';
import PropertyCard from './common/PropertyCard';
import CustomButton from './common/CustomButton';
// charts
import PieChart from './charts/PieChart';
import PropertyReferrals from './charts/PropertyReferrals';
import TotalRevenue from './charts/TotalRevenue';
// agent
import AgentCard from './agent/AgentCard';
// home
import TopAgent from './home/TopAgent';
export {
Profile,
PropertyCard,
CustomButton,
PieChart,
PropertyReferrals,
TotalRevenue,
AgentCard,
TopAgent,
};
export const propertyReferralsInfo = [
{
title: 'Social Media',
percentage: 64,
color: '#6C5DD3',
},
{
title: 'Marketplace',
percentage: 40,
color: '#7FBA7A',
},
{
title: 'Websites',
percentage: 50,
color: '#FFCE73',
},
{
title: 'Digital Ads',
percentage: 80,
color: '#FFA2C0',
},
{
title: 'Others',
percentage: 15,
color: '#F45252',
},
];
* {
font-family: 'Manrope', sans-serif !important;
}
a {
text-decoration: none !important;
}
.my_profile-bg {
width: 340px;
border-top-left-radius: 15px;
border-bottom-left-radius: 15px;
}
.my_profile_user-img {
border-radius: 100%;
margin-left: -64px;
}
.property_details-img {
width: 100%;
}
@media screen and (max-width: 900px) {
.my_profile-bg {
width: 100%;
border-radius: 15px;
}
.my_profile_user-img {
margin-left: 0px;
margin-top: -64px;
}
.property_details-img {
width: 100%;
height: auto;
}
}
import { useState } from 'react';
import { useGetIdentity } from '@pankod/refine-core';
import { FieldValues, useForm } from '@pankod/refine-react-hook-form';
import Form from 'components/common/Form';
const CreateProperty = () => {
const { data: user } = useGetIdentity();
const [propertyImage, setPropertyImage] = useState({ name: '', url: '' });
const { refineCore: { onFinish, formLoading }, register, handleSubmit } = useForm();
const handleImageChange = (file: File) => {
const reader = (readFile: File) => new Promise<string>((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = () => resolve(fileReader.result as string);
fileReader.readAsDataURL(readFile);
});
reader(file).then((result: string) => setPropertyImage({ name: file?.name, url: result }));
};
const onFinishHandler = async (data: FieldValues) => {
if(!propertyImage.name) return alert('Please select an image');
await onFinish({ ...data, photo: propertyImage.url, email: user.email })
};
return (
<Form
type="Create"
register={register}
onFinish={onFinish}
formLoading={formLoading}
handleSubmit={handleSubmit}
handleImageChange={handleImageChange}
onFinishHandler={onFinishHandler}
propertyImage={propertyImage}
/>
)
}
export default CreateProperty
import { useState } from 'react';
import { useGetIdentity } from '@pankod/refine-core';
import { FieldValues, useForm } from '@pankod/refine-react-hook-form';
import Form from 'components/common/Form';
const CreateProperty = () => {
const { data: user } = useGetIdentity();
const [propertyImage, setPropertyImage] = useState({ name: '', url: '' });
const { refineCore: { onFinish, formLoading }, register, handleSubmit } = useForm();
const handleImageChange = (file: File) => {
const reader = (readFile: File) => new Promise<string>((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = () => resolve(fileReader.result as string);
fileReader.readAsDataURL(readFile);
});
reader(file).then((result: string) => setPropertyImage({ name: file?.name, url: result }));
};
const onFinishHandler = async (data: FieldValues) => {
if (!propertyImage.name) return alert('Please upload a property image');
await onFinish({ ...data, photo: propertyImage.url, email: user.email });
};
return (
<Form
type="Edit"
register={register}
onFinish={onFinish}
formLoading={formLoading}
handleSubmit={handleSubmit}
handleImageChange={handleImageChange}
onFinishHandler={onFinishHandler}
propertyImage={propertyImage}
/>
);
};
export default CreateProperty;
import AgentProfile from './agent-profile';
import Agents from './agent';
import AllProperties from './all-properties';
import CreateProperty from './create-property';
import Home from './home';
import { Login } from './login';
import MyProfile from './my-profile';
import PropertyDetails from './property-details';
import EditProperty from './edit-property';
export {
AgentProfile,
Agents,
AllProperties,
CreateProperty,
Home,
Login,
MyProfile,
PropertyDetails,
EditProperty,
};
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200;300;400;500;600;700;800&display=swap" rel="stylesheet">
/* eslint-disable no-plusplus */
import { FormValues } from 'interfaces/property';
export const validateForm = (formValues: FormValues) => {
const errors: { message: string } = { message: '' };
let hasError = false;
Object.keys(formValues).forEach((key) => {
switch (key) {
case 'title':
if (!formValues.title) {
errors.message = 'Title is required';
hasError = true;
}
break;
case 'description':
if (!formValues.description) {
errors.message = 'Description is required';
hasError = true;
}
break;
case 'propertyType':
if (!formValues.propertyType) {
errors.message = 'Property type is required';
hasError = true;
}
break;
case 'location':
if (!formValues.location) {
errors.message = 'Location is required';
hasError = true;
}
break;
case 'price':
if (!formValues.price) {
errors.message = 'Price is required';
hasError = true;
}
break;
default:
hasError = false;
}
});
return { hasError, errors };
};
export const hasChanged = (initialValues: FormValues, currentValues: FormValues) => {
const initialValuesArray = Object.values(initialValues);
const currentValuesArray = Object.values(currentValues);
for (let i = 0; i < initialValuesArray.length; i++) {
if (initialValuesArray[i] !== currentValuesArray[i]) {
return true;
}
}
return false;
};
@Robj1925
Copy link

Robj1925 commented Jun 7, 2023

when I install refine, the component only has a header, no siders, what's the solution

@sujoyduttajad
Copy link

Does anyone was successful in implementing the DarkMode toggle

Please let me know how you did it, I tried but just couldn't implement it

@khatiazitanishvili
Copy link

when I install refine, the component only has a header, no siders, what's the solution

@rounitverma
Copy link

it won't throw an error as siders and other parameters are not being imported. Just move ahead

@zmanhcong
Copy link

when I install refine, the component only has a header, no siders, what's the solution

same issue, it seem refine was update neweast version so we have to refactor the code.

@Yosef-Ali
Copy link

when I install refine, the component only has a header, no siders, what's the solution

same issue, it seem refine was update neweast version so we have to refactor the code.

Run the swizzle command in the project directory i fund in the doc npm run refine swizzle

@shithinshetty
Copy link

Screenshot 2023-03-11 at 1 58 10 PM

i'm facing an error in login with google. A popup window opens with no content can someone help me out?

While Creating OAuth CRED change the https://localhost:3000 to http://localhost:3000

@saibadarinadh
Copy link

image

@dipak-wagh
Copy link

in above validateForm file,i used in my project.but it gives error ->interface/property cannot find.

@ArfaniAsra
Copy link

when I install refine, the component only has a header, no siders, what's the solution
same issue, it seem refine was update neweast version so we have to refactor the code.

Run the swizzle command in the project directory i fund in the doc npm run refine swizzle

when I install refine, the component only has a header, no siders, what's the solution
same issue, it seem refine was update neweast version so we have to refactor the code.

Run the swizzle command in the project directory i fund in the doc npm run refine swizzle

Hi, I want to ask. after running this command, what should we choose between 3 of these following items:
Data Provider
@refinedev/simple-rest
UI Framework
@refinedev/core
@refinedev/mui

@sayanbiswas0408
Copy link

Can anyone send the full code repository with latest dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment