diff --git a/api/go.mod b/api/go.mod
index 2980558..a8cdb08 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -38,8 +38,9 @@ require (
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
+ golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/net v0.10.0 // indirect
- golang.org/x/sys v0.8.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/api/go.sum b/api/go.sum
index 5b639a3..31d676b 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -105,6 +105,8 @@ golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
@@ -116,6 +118,7 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/api/src/model/types.go b/api/src/model/types.go
index c203c05..29c69b6 100644
--- a/api/src/model/types.go
+++ b/api/src/model/types.go
@@ -1,9 +1,13 @@
package model
import (
+ "errors"
+ "regexp"
+ "time"
+
"github.com/lib/pq"
+ "golang.org/x/exp/slices"
"gorm.io/gorm"
- "time"
)
type Gift struct {
@@ -13,6 +17,8 @@ type Gift struct {
Link string
Description string
Demographic string
+ Category pq.StringArray `gorm:"type:text[]"`
+ Occasion string
GiftCollections []*GiftCollection `gorm:"many2many:gift_request_gifts;"`
}
@@ -66,3 +72,226 @@ type Admin struct {
UserID uint
User User
}
+
+func (gift *Gift) BeforeSave(tx *gorm.DB) (err error) {
+ if len(gift.Name) == 0 {
+ err = errors.New("gift name cannot be empty")
+ return err
+ }
+
+ if gift.Price < 0 {
+ err = errors.New("gift must have a price")
+ return err
+ }
+
+ // if a gift has no link
+ if len(gift.Link) == 0 {
+ err = errors.New("gift must have a link")
+ return err
+ }
+
+ Demographics := []string{
+ "For her",
+ "For him",
+ "For kids",
+ "For mom",
+ "For dad",
+ "For women",
+ "For men",
+ }
+
+ for _, demographic := range Demographics {
+ if !slices.Contains(Demographics, demographic) {
+ err = errors.New("gift must have a valid demographic")
+ return err
+ }
+ }
+
+ Occasions := []string{
+ "Birthday",
+ "Bridal",
+ "Get well soon",
+ "New baby",
+ "Thinking of you",
+ "Thank you",
+ }
+
+ for _, occasion := range Occasions {
+ if !slices.Contains(Occasions, occasion) {
+ err = errors.New("gift must have a valid occasion")
+ return err
+ }
+ }
+
+ Categories := []string{
+ "Best selling",
+ "Fun",
+ "Gadgets",
+ "Home",
+ "Jewelry",
+ "Kitchen & bar",
+ "Warm and cozy",
+ }
+
+ for _, category := range Categories {
+ if !slices.Contains(Categories, category) {
+ err = errors.New("gift must have a valid category")
+ return err
+ }
+ }
+
+ // if a gift has no description
+ if len(gift.Description) == 0 {
+ err = errors.New("gift must have a description")
+ return err
+ }
+
+ return
+}
+
+func (gc *GiftCollection) BeforeSave(tx *gorm.DB) (err error) {
+ // if collection name is not set
+ if len(gc.CollectionName) == 0 {
+ err = errors.New("giftCollection must have a name")
+ return err
+ }
+
+ // if customer is not found
+ if gc.Customer == nil {
+ err = errors.New("giftCollection must have a customer")
+ return err
+ }
+
+ return
+}
+
+func (user *User) BeforeSave(tx *gorm.DB) (err error) {
+ if len(user.FirstName) == 0 {
+ err = errors.New("user must have a first name")
+ return err
+ }
+
+ if len(user.LastName) == 0 {
+ err = errors.New("user must have a last name")
+ return err
+ }
+
+ if len(user.Password) == 0 {
+ err = errors.New("Please enter a password")
+ return err
+ }
+
+ // use regex to validate email
+ pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
+ regex := regexp.MustCompile(pattern)
+
+ // Use the MatchString function to check if the text matches the pattern
+ if regex.MatchString(user.Email) == false {
+ err = errors.New("user email must be a valid email")
+ return err
+ }
+
+ return
+}
+
+func (customer *Customer) BeforeSave(tx *gorm.DB) (err error) {
+ // if giftRequests is not empty or not populated
+ if customer.GiftRequests == nil {
+ err = errors.New("customer must have a giftRequests")
+ return err
+ }
+
+ return
+}
+
+func (giftRequest *GiftRequest) BeforeSave(tx *gorm.DB) (err error) {
+ // if recipient name is not set
+ if len(giftRequest.RecipientName) == 0 {
+ err = errors.New("giftRequest must have a recipient name")
+ return err
+ }
+
+ // if recipient age is not set
+ if giftRequest.RecipientAge < 1 || giftRequest.RecipientAge > 150 {
+ err = errors.New("giftRequest must have a valid recipient age")
+ return err
+ }
+
+ GiftOccasions := []string{
+ "Birthday",
+ "Bridal",
+ "Get well soon",
+ "New baby",
+ "Thinking of you",
+ "Thank you",
+ }
+
+ // if occasion is not in GiftOccasions
+ if giftRequest.Occasion != nil {
+ for _, occasion := range giftRequest.Occasion {
+ if !slices.Contains(GiftOccasions, occasion) {
+ err = errors.New("giftRequest must have a valid occasion")
+ return err
+ }
+ }
+ } else {
+ err = errors.New("giftRequest must have an occasion")
+ return err
+ }
+
+ Interests := []string{
+ "Best selling",
+ "Fun",
+ "Gadgets",
+ "Home",
+ "Jewelry",
+ "Kitchen & bar",
+ "Warm and cozy",
+ }
+
+ // if interests is not in Interests
+ if giftRequest.RecipientInterests != nil {
+ for _, interest := range giftRequest.RecipientInterests {
+ if !slices.Contains(Interests, interest) {
+ err = errors.New("giftRequest must have a valid interest")
+ return err
+ }
+ }
+ } else {
+ err = errors.New("giftRequest must have an interest")
+ return err
+ }
+
+ // if either budget is below negative
+ if giftRequest.BudgetMax < 0 || giftRequest.BudgetMin < 0 {
+ err = errors.New("giftRequest budget cannot be negative")
+ return err
+ }
+
+ // if max budget is less than min budget
+ if giftRequest.BudgetMax <= giftRequest.BudgetMin {
+ err = errors.New("giftRequest max budget must be greater than min budget")
+ return err
+ }
+
+ // if date needed is not set
+ if giftRequest.DateNeeded.IsZero() {
+ err = errors.New("giftRequest must have a date needed")
+ return err
+ } else if giftRequest.DateNeeded.Before(time.Now()) {
+ // if date needed is in the past
+ err = errors.New("giftRequest date needed must be in the future")
+ return err
+ }
+
+ return
+}
+
+func (giftResponse *GiftResponse) BeforeSave(tx *gorm.DB) (err error) {
+ if giftResponse.CustomMessage == "" {
+ err = errors.New("giftResponse must have a custom message")
+ return err
+ }
+
+ return
+}
diff --git a/api/tests/db_test.go b/api/tests/db_test.go
index 5719ba9..f6913d4 100644
--- a/api/tests/db_test.go
+++ b/api/tests/db_test.go
@@ -2,11 +2,12 @@ package tests
import (
"CaitsCurates/backend/src/model"
- "github.com/stretchr/testify/assert"
"os"
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
@@ -274,6 +275,7 @@ func TestGiftResponseModel(t *testing.T) {
CollectionName: "Cool Toys",
Gifts: []*model.Gift{&gift1, &gift2},
}
+
// Save the gifts
tx.Save(&gift1)
tx.Save(&gift2)
diff --git a/client/src/App.tsx b/client/src/App.tsx
index b8e23cd..3c07d8e 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -1,19 +1,21 @@
import {
- BrowserRouter as Router,
- Route,
- Routes,
+ BrowserRouter as Router,
+ Route,
+ Routes,
} from 'react-router-dom';
+import GiftManagementPage from './pages/GiftManagementPage';
import HomePage from './pages/HomePage';
function App() {
- return (
-
Price: ${props.price}
+ Buy Now +Demographic: {props.demographic}
+Description: {props.description}
+Collections: {props.giftCollections}
+